web-dev-qa-db-ja.com

参加時にOracleがインデックスを使用しない

計画の索引付けと説明は非常に新しいので、ご容赦ください。クエリを調整しようとしていますが、問題が発生しています。

私は2つのテーブルを持っています:

SKU
------
SKUIDX (Unique index)
CLRIDX (Index)
..
..

IMPCOST_CLR
-----------
ICCIDX (Unique index)
CLRIDX (Index)
...
..

select * from SKU where clridx = 122を実行すると、Explainプランでインデックスを使用していることがわかります(TABLE ACCESS .. INDEXと表示され、OBJECT_NAMEの下にインデックス名が表示され、オプションはRANGE SCANです)。

同じフィールドで結合しようとすると、インデックスを使用していないように見えます(TABLE ACCESS .. HASH JOINと表示され、オプションの下にFULLと表示されます)。

インデックスを使用していない理由を確認するには、何を探す必要がありますか?申し訳ありませんが、これを表示するために入力するコマンドがわかりません。詳細が必要な場合はお知らせください。

例:
最初のクエリ:

  SELECT
    *
  FROM
    AP21.SKU
  WHERE
    CLRIDX = 100

enter image description here

2番目のクエリ:

  SELECT
    *
  FROM
    AP21.IMPCOST_CLR
  WHERE
    CLRIDX = 100

enter image description here

3番目のクエリ:

  SELECT
    *
  FROM
    AP21.SKU
  INNER JOIN
    AP21.IMPCOST_CLR ON
    IMPCOST_CLR.CLRIDX = SKU.CLRIDX

enter image description here

8
Lock

このクエリを見てください:

SELECT
    *
FROM
    AP21.SKU
INNER JOIN
    AP21.IMPCOST_CLR ON
    IMPCOST_CLR.CLRIDX = SKU.CLRIDX

追加の述語はありません。したがって、SKUのすべての行をIMPCOST_CLRのすべての行に結合します。さらに、両方のテーブルからすべての列を選択しています。

これは、Oracleが両方のテーブル全体を読み取る必要があることを意味します。これを行う最も効率的な方法は、全表スキャンを使用して、マルチブロック読み取りですべての行をすくい上げ、ハッシュを使用して結合の値を一致させることです。

基本的に、これは集合演算であり、SQLが非常にうまく機能しますが、インデックス付きの読み取りはもっと [〜#〜] rbar [〜#〜] です。ここで、3番目のクエリを変更して、次のような追加の述語を含めると、

WHERE SKU.CLRIDX = 100

ほとんどの場合、アクセスパスがINDEX RANGESCANに戻ります。比較的少数の行しか選択していないため、インデックス付きの読み取りが再びより効率的なパスになります。


「調整しようとしているクエリは何百もの長いものですが、それを分解して段階的に実行します!」

これは優れた手法ですが、Oracleオプティマイザがどのように機能するかを理解する必要があります。 ExplainPlanにはたくさんの情報があります。 詳細をご覧ください。 各ステップのRows列の値に注意してください。これは、オプティマイザーが操作から取得すると予想する行数を示しています。最初の2つのクエリの値は、3番目のクエリとは大きく異なります。

18
APC

同じフィールドで結合しようとすると、インデックスを使用していないように見えます(TABLE ACCESS .. HASH JOINと表示され、オプションの下にFULLと表示されます)。

これは、HASH JOINが結合述部でインデックスを使用(必要)しないためです。

http://use-the-index-luke.com/sql/join/hash-join-partial-objects

6
Markus Winand