2011-07-26 11 views
3

Oracle 10gを使用しています。ここに私のクエリですIN句の最適化

select * from Entries 
where RefKey in (select RefKey 
       from Entries 
       where KeyStat = 1) 
and RefKey = Key; 

ここでは、RefKey、KeyおよびKeyStatがすべて索引付けされています。テーブルはここでは使用されていない別のカラムに分割されています。 このクエリでは、現在アクティブな(KeyStat = 1)マスターキー(RefKey = Key、マスターの場合)を選択しています。 SQLTools 1.21 RC3を使用してこのクエリの実行計画を示します。

---------------------------------------------------------------------------------------------------------------------- 
| Id | Operation       | Name   | Rows | Bytes | Cost (%CPU)| Time  | Pstart| Pstop | 
---------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT     |    |  1 | 270 | 218K (1)| 00:43:37 |  |  | 
| 1 | NESTED LOOPS SEMI     |    |  1 | 270 | 218K (1)| 00:43:37 |  |  | 
| 2 | PARTITION RANGE ALL    |    |  1 | 262 | 218K (1)| 00:43:37 |  1 | 12 | 
|* 3 | TABLE ACCESS FULL    | ENTRIES  |  1 | 262 | 218K (1)| 00:43:37 |  1 | 12 | 
|* 4 | TABLE ACCESS BY GLOBAL INDEX ROWID| ENTRIES  | 10M| 77M|  3 (0)| 00:00:01 | ROWID | ROWID | 
|* 5 | INDEX RANGE SCAN     | IND_ENTR_REFKEY|  1 |  |  2 (0)| 00:00:01 |  |  | 
---------------------------------------------------------------------------------------------------------------------- 

私はID = 3 "TABLE ACCESS FULL"について懸念しています。この問合せで使用されているすべての列が索引付けされている場合、oracleが全表スキャンを実行する理由

これはどのように最適化できますか?内部クエリにいくつかの値を入れると、はるかに高速に戻ります。


サブクエリが必要な理由を説明する:少なくとも1つのアクティブなキーを持つバッチ全体を選択しています。 Refkeyは一意ではありません。例えば:

Key=1, RefKey=1, Stat=1 
Key=2, RefKey=1, Stat=0 
Key=3, RefKey=2, Stat=1 
+0

画像をアップロードすることができず、上記の実行計画が正しくフォーマットされていませんでした。申し訳ありません。 – bjan

+0

テーブルに統計情報を収集しようとしましたか? –

答えて

5

表アクセスFULL「私は3 = IDが心配です 『』すべての列 がこのクエリで使用されている場合は、Oracleがフル テーブルスキャンをやっている理由。その後、インデックスが作成されます。」

オプティマイザは、KEYSTATのインデックスを無視しています。 KEYSTATは非常に選択的ではなく(比較的少数の異なる値)、ENTRIESテーブルの全範囲に均等に分散されているためです。クエリがテーブル内のすべてのブロックにほとんどヒットする場合は、FULL TABLE SCANが最適なパスです。

この推測は、サブクエリをフィルタリングすることで得られるスピードの向上によって検証されます。

他の人が示唆しているように、サブクエリを削除するためにステートメントをリファクタリングすると、パフォーマンスを向上させる最善の方法になります。


「KeyStat = 0は、わずか数 1000ではとても有益であるインデックスを使用して1を持つことになります持つ数百万のエントリがあるでしょう。」

歪んだデータ配信は、パフォーマンス上の問題の原因となることがよくあります。あなたは、事実は、データベースはは、は、KEYSTAT = 1がKEYSTAT = 0よりもはるかに選択的であることを知りません。私たちがそれを伝えない限り、あなたはそのインデックスに関する統計を収集するときにヒストグラムを作成することを検討したいかもしれません。 Find out more

ヒストグラムは、特にリテラルのバインド変数を使用するクエリで問題を発生させたり解決したりする可能性があることに注意してください。だから生産に移す前に砂場でベンチマークをしてください。

+0

KeyStat = 0のエントリが何百万もありますが、1000sにはわずか1しかないため、インデックスを使用すると有益になります。たとえば、サンプルDB iには1つのレコードが5つしかなく、20105126には0が含まれています – bjan

4

多分私は何かが恋しいですが、これは同じ結果をもたらさないでしょうか?

select * 
from Entries e 
where e.KeyStat = 1 
    and e.RefKey = e.Key 
1

は、あなたが最後に余分な情報の束と実行計画を取得する必要があります

EXPLAIN PLAN FOR select * from Entries 
where RefKey in (select RefKey 
       from Entries 
       where KeyStat = 1) 
and RefKey = Key; 

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); 

を行うことができます。具体的には、その操作に関心があります3.完全なテーブルスキャンを行うだけでなく、行/カーディナリティーが1になっているだけです。実際には何も見つからないと思われますそこにゼロの値を与える)。

オペレーション4では約1,000万行を話しますが、コストは「3」、インデックスコストは「2」なので、行を見つけることは期待できません。 '3'から何かを見つけるためのスキャンは期待していないので、インデックススキャンに値を入力することは決してないので、決して10Mの行を見ることはありません。

私には2つの問題があります。まず、KeyStatのインデックスは使用しません。第2に、マッチによって返される行の数を過小評価しています。最初はデータ型の不一致が原因である可能性があります。たぶん、KeyStatは文字値です。たぶんそれはインデックスの先頭の列ではないでしょう。インデックスが無効になっている可能性があります(ETLジョブ中)。

奇数推定も示唆的です。列がインデックスの先頭の列であった場合、統計情報はその列のmax_valが1であると考えられます。max_valがゼロであると考えると、「あなたは見つからないでしょう何か "を見積もるだけでなく、max_valをすばやく見つけるために使用するインデックスを持っていないことも示しています。