11

次の形式のような SQL クエリを使用しています。

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
AND table1.period = table2.period

そして、戻るのに少なくとも4分かかるため、遅すぎるか、何かがデッドロックしています. これを次のように変更するとします。

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table1.period = table2.period

その後、正常に動作します(ただし、正しい数の列が返されません)。これをスピードアップする方法はありますか?

UPDATE : 後者のクエリの最後の 2 行を切り替えると、同じことが行われます。

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.period = table2.period
WHERE table1.person_uid = table2.person_uid

更新 2: これらは実際に私が参加しているビューです。残念ながら、それらは私が制御できないデータベース上にあるため、インデックスを (簡単に) 変更することはできません。ただし、これはインデックス作成の問題であることに同意する傾向があります。私が知らないこのクエリを調整する魔法の方法がある場合に備えて、回答を受け入れる前に少し待ちます。それ以外の場合は、現在の回答のいずれかを受け入れて、やりたいことを行う別の方法を見つけようとします。これまでお世話になりました。

4

8 に答える 8

16

ステートメント 2 と 3 は最初のステートメントとは異なることに注意してください。

どのように?さて、あなたは左外部結合を行っていますが、WHERE 句はそれを考慮していません (ON 句のように)。少なくとも、次を試してください。

SELECT col1, col2
FROM table1, table2
WHERE table1.person_uid = table2.person_uid (+)
AND table1.period = table2.period (+)

同じパフォーマンスの問題が発生するかどうかを確認してください。

これらのテーブルにはどのようなインデックスがありますか? この関係は外部キー制約によって定義されていますか?

おそらく必要なのは、person_uid と period の両方 (両方のテーブル) の複合インデックスです。

于 2009-01-14T21:52:16.253 に答える
5

最後の2つが最初のクエリと同じクエリではない理由を理解する必要があると思います。左結合を実行してから、結合の右側にあるテーブルのフィールド(最初のテーブルと一致するレコードが常にあるとは限らないフィールド)を参照するwhere句を追加すると、結合が効果的に次のように変更されます。内部結合。これには1つの例外があります。それは、次のようなものを参照する場合です。

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table2.person_uid is null

この場合、2番目のテーブルにレコードがないレコードを要求します。ただし、この特殊なケースを除いて、where句でtable2のフィールドを参照すると、左結合が内部結合に変更されます。

クエリの速度が十分でない場合は、インデックス作成を確認します。

于 2009-01-15T01:35:46.333 に答える
4

あなたが提供した情報に基づいて誰かがあなたに言うことはすべて推測です.

クエリの実行計画を見てください。計画が遅い理由がわからない場合は、ここに計画を投稿してください。

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/ex_plan.htm#PFGRF009

于 2009-01-15T18:16:37.390 に答える
2

これらのテーブルには、結合する列にインデックスがありますか? Oracle の無料の SQLDeveloper 製品をインストールし、それを使用してそのクエリを「説明」し、両方のテーブルのシーケンシャル スキャンを実行しているかどうかを確認します。

于 2009-01-14T21:50:11.097 に答える
2

左結合では、(person_uid,period) の一意の組み合わせごとに table1 をスキャンし、そこにあるすべての対応するレコードを table2 で検索します。table2 に適切なインデックスがない場合、そのテーブル全体もスキャンする必要があります。

私の最善の推測では、実行計画を見ずに、最初のクエリ (正しいと思われる唯一のクエリ) が table1 だけでなく table2 もテーブル スキャンする必要があるということです。

インデックスを変更できないと言うように、クエリを変更する必要があります。私の知る限り、現実的な選択肢は 1 つしかありません...

SELECT
   col1, col2
FROM
   table2
FULL OUTER JOIN
   table1
      ON table1.person_uid = table2.person_uid
      AND table1.period = table2.period
WHERE
   table1.person_uid IS NOT NULL

ここでの希望は、(person_uid, period) の一意の組み合わせごとに table2 をスキャンすることですが、table1 のインデックスを利用することです。(テーブル1をスキャンしてテーブル2のインデックスを使用するのとは対照的に、これはクエリから期待したものです。)

ただし、table1 に適切なインデックスがない場合、パフォーマンスの向上が見られる可能性はほとんどありません...

民主党。

于 2009-01-15T16:50:21.357 に答える
0

ANSI 結合構文は、JOIN 条件と FILTER 述語を明確に区別しています。これは、外部結合を記述するときに非常に重要です。emp/dept テーブルを使用して、次の 2 つの外部結合の結果を確認します。

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
and loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
RESEARCH               20                       DALLAS
SALES                  30                       CHICAGO
OPERATIONS             40                       BOSTON

====

Q2
SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
where loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
OPERATIONS             40                       BOSTON

Q1が示す最初の例は、「定数での結合」の例です。基本的に、フィルター条件は、外部結合を実行する前に適用されます。そのため、行を削除すると、後で外部結合の一部として追加されます。必ずしも間違っているわけではありませんが、それはあなたが本当に求めていたクエリですか? 多くの場合、必要なのは Q2 に示されている結果であり、(外部) 結合の後にフィルターが適用されます。

大規模なデータセットの場合、パフォーマンスへの影響もあります。多くの場合、定数の結合は、ラテラル ビューを作成することによって、オプティマイザーによって内部的に解決される必要があります。これは、通常、ハッシュ結合ではなく、ネストされたループ結合を介してのみ最適化できます。

Oracle の外部結合構文に精通している開発者の場合、クエリはおそらく次のように記述されているはずです。

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
        ,emp e
where  d.deptno = e.deptno(+)
and loc in ('NEW YORK','BOSTON' )

このクエリは、上記の Q2 と意味的に同等です。

要約すると、ANSI 外部結合を記述する場合、JOIN 句と WHERE 句の違いを理解することが非常に重要です。

于 2017-01-08T18:45:52.327 に答える