2015-12-18 12 views
12

これは、2つのインデックスを結合すると単純化されたパフォーマンスの問題です。2つのインデックスでMERGE JOINがSORTの原因となっていますか?

この2つのテーブルをLEFT OUTER JOINして、すでにインデックスされているIDフィールドのみを出力したいとします。

SELECT ZZ_BASE.ID 
FROM ZZ_BASE 
LEFT OUTER JOIN ZZ_CHILD ON (ZZ_BASE.ID = ZZ_CHILD.ID); 
---------------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
---------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |  | 1000K| 9765K|  | 4894 (2)| 00:00:30 | 
|* 1 | HASH JOIN OUTER  |  | 1000K| 9765K| 16M| 4894 (2)| 00:00:30 | 
| 2 | INDEX FAST FULL SCAN| ZZ_B_I | 1000K| 4882K|  | 948 (3)| 00:00:06 | 
| 3 | INDEX FAST FULL SCAN| ZZ_C_I | 1000K| 4882K|  | 948 (3)| 00:00:06 | 
---------------------------------------------------------------------------------------- 

テーブルアクセスは必要ないとわかるように、インデックスアクセスのみです。しかし、常識的に、HASH結合は、これらの2つのインデックスを結合する最も最適な方法ではありません。これらの2つのテーブルがはるかに大きい場合は、非常に大きなハッシュテーブルを作成する必要があります。

もっと効率的な方法は、2つのインデックスを並べ替えることです。

SELECT /*+ USE_MERGE(ZZ_BASE ZZ_CHILD) */ ZZ_BASE.ID 
FROM ZZ_BASE 
LEFT OUTER JOIN ZZ_CHILD ON (ZZ_BASE.ID = ZZ_CHILD.ID); 
----------------------------------------------------------------------------------------- 
| Id | Operation    | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |  | 1000K| 9765K|  | 6931 (3)| 00:00:42 | 
| 1 | MERGE JOIN OUTER  |  | 1000K| 9765K|  | 6931 (3)| 00:00:42 | 
| 2 | INDEX FULL SCAN  | ZZ_B_I | 1000K| 4882K|  | 2258 (2)| 00:00:14 | 
|* 3 | SORT JOIN   |  | 1000K| 4882K| 22M| 4673 (4)| 00:00:29 | 
| 4 | INDEX FAST FULL SCAN| ZZ_C_I | 1000K| 4882K|  | 948 (3)| 00:00:06 | 
----------------------------------------------------------------------------------------- 

しかし、2番目のインデックスが、それはすでにインデックスが存在する場合、データベースは最初のデータセットをソートを回避することができます」(ある場合でも、ソートされます。ただし、データベースは常に第二のデータセットをソートすることが表示されます関係なく、インデックスの」1

は基本的に、私が欲しいのはつまり、SORT-MERGEが参加し、瞬時に、レコードの出力を開始する使用するクエリされています。それは最初に持っているので

  • なしハッシュ結合します作る ハッシュテーブル(ディスク上に格納されている場合はIOオーバーヘッド)は瞬時に出力されません。
  • いいえNESTED LOOP joinは、即時に を出力しますが、索引ポークにlog(N)複雑さがあり、索引が大きい場合に非順次索引読取りに大きなIOオーバーヘッドがあります。
+0

Oracleは時々パススルーソート(何もしないし、非ブロッキングである)NO_SORTのようなものを標識されている実行し、私はそれがかもしれないと仮定この場合には適用されます(少なくとも、そうでなければなりません)。 –

+0

引用符で囲まれたコメント(source?)は、テーブルスキャンにも適用されます。インデックススキャンには必要ありません。 –

+2

インデックスが大きい場合に、非シーケンシャルインデックス読み込みでIOオーバーヘッドが大きくなります._インデックスをインデックス順ディスクレベルでの非シーケンシャルIOも可能です。インデックス高速フルスキャンでは順次IOを実行できますが、ソートされていない順序でデータが取得されます。索引はディスク上に順番にレイアウトされていません。 –

答えて

1

INDEX_ASC(または単にINDEX)は、パフォーマンスを実際のデータと比較するために試してみると便利なヒントです。

B *ツリーインデックスがNULLキーを見つけることができず、ZZ_BASEにNOT NULLという制約がないため、外側の行ソースに対してインデックススキャンを実行するのに少し驚いています。それを追加してもう少しヒントを付けると、ZZ_C_Iインデックスのインデックス順でフルスキャンが実行されます。残念ながら、SORT JOINの手順は保存されませんが、データが既にソートされているため、少なくとも高速である必要があります(O(n))。

alter table zz_base modify (id not null); 
SELECT 
    /*+ leading(zz_base) USE_MERGE(ZZ_CHILD) 
     index_asc(zz_base (id)) index(zz_child (id)) */ ZZ_BASE.ID 
FROM ZZ_BASE left outer join ZZ_CHILD on zz_base.id=zz_child.id; 

このクエリは、次の実行計画を使用しています。

------------------------------------------------------------------------------------ 
| Id | Operation   | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT |  | 1000K| 9765K|  | 8241 (3)| 00:00:50 | 
| 1 | MERGE JOIN OUTER |  | 1000K| 9765K|  | 8241 (3)| 00:00:50 | 
| 2 | INDEX FULL SCAN | ZZ_B_I | 1000K| 4882K|  | 2258 (2)| 00:00:14 | 
|* 3 | SORT JOIN  |  | 1000K| 4882K| 22M| 5983 (3)| 00:00:36 | 
| 4 | INDEX FULL SCAN| ZZ_C_I | 1000K| 4882K|  | 2258 (2)| 00:00:14 | 
------------------------------------------------------------------------------------ 
+0

あなたは、ここではNOT NULL制約が必要であると言っています。私はテストを再開しました。この制約を追加すると、2番目の実行計画しか得られません。私はそれを逃した方法を知らない。そしてあなたは正しいです。ヒントは実際にZZ_CHILDテーブルのINDEX FULL SCANを強制します。良いですね!そして、stackoverflowへようこそ!あなたの答えに実行計画を追加します。 –

関連する問題