3

Oracle 10g を使用しています。これが私のクエリです

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

ここでは、RefKey、Key、KeyStat のすべてにインデックスが付けられています。テーブルは、ここでは使用されていない別の列で分割されています。このクエリでは、現在アクティブなマスター キー (RefKey = Key then master の場合) (KeyStat = 1) を選択しています。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」が気になります。このクエリで使用されているすべての列にインデックスが付けられている場合、オラクルがフルテーブルスキャンを実行する理由.

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


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

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

3 に答える 3

5

「ID = 3 "TABLE ACCESS FULL" が心配です。このクエリで使用されているすべての列にインデックスが付けられている場合、オラクルがフル テーブル スキャンを実行しているのはなぜですか。」

オプティマイザは KEYSTAT のインデックスを無視しています。これは、KEYSTAT があまり選択的ではない (個別の値が比較的少ない) ため、および/またはそれらの値が ENTRIES テーブルの範囲全体に均等に分散されているためだと思います。クエリがテーブル内のほぼすべてのブロックにヒットする場合は、FULL TABLE SCAN が最適な方法です。

この推測は、サブクエリをフィルタリングすることによって得られる高速化によって検証されます。

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


「KeyStat= 0 のエントリは数百万ありますが、1 のエントリは 1000 の中でわずかしかないため、インデックスを使用すると有益です。」

偏ったデータ分散は、パフォーマンスの問題の原因となることがよくあります。おわかりのように、データベースはKEYSTAT=1 が KEYSTAT=0 よりもはるかに選択的であることを知りません。明示しない限り、そのインデックスの統計を収集するときにヒストグラムの作成を検討する必要があるのはそのためです。 詳細をご覧ください

ヒストグラムは、特にリテラルの代わりにバインド変数を使用するクエリで、問題を解決するだけでなく問題を引き起こす可能性があることに注意してください。そのため、本番環境に入れる前にサンドピットでベンチマークを行ってください。

于 2011-07-26T07:52:29.403 に答える
4

多分私は何かを見落としているかもしれませんが、これは同じ結果をもたらすべきではありませんか?

select *
from Entries e
where e.KeyStat = 1 
  and e.RefKey = e.Key
于 2011-07-26T07:38:58.000 に答える
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」からのスキャンで何かが見つかるとは想定していないため、インデックス スキャンに値を差し込むことは想定されていないため、1,000 万行が表示されることはありません。

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

奇妙な見積もりも示唆的です。列がインデックスの先頭の列である場合、列の max_val が 1 であることが統計でわかっていると思います。なんでも」の見積もりだけでなく、max_val をすばやく見つけるために使用するインデックスがありませんでした。

于 2011-07-26T10:04:03.727 に答える