次のような2つのテーブルがあります。
Event
id
type
... a bunch of other columns
ProcessedEvent
event_id
process
に定義されたインデックスがあります
- イベント(ID)(PK)
- ProcessedEvent(event_id、process)
1つ目は、アプリケーションのイベントを表します。
2つ目は、特定のイベントが特定のプロセスによってプロセスを取得したという事実を表しています。特定のイベントを処理する必要のあるプロセスは多数あるため、最初のエントリごとに2番目のテーブルに複数のエントリがあります。
処理が必要なすべてのイベントを見つけるために、次のクエリを実行します。
select * // of course we do name the columns in the production code
from Event
where type in ( 'typeA', 'typeB', 'typeC')
and id not in (
select event_id
from ProcessedEvent
where process = :1
)
統計は最新です
ほとんどのイベントが処理されるので、最適な実行プランは次のようになります。
- ProcessedEventインデックスの完全なインデックススキャン
- イベントインデックスのフルインデックススキャン
- 2つの間の反結合
- 残りのテーブルへのアクセス
- フィルター
代わりに、Oracleは次のことを行います
- ProcessedEventインデックスの完全なインデックススキャン
- イベントテーブルの全表スキャン
- イベントテーブルをフィルタリングする
- 2つのセット間のアンチ結合
インデックスのヒントを使用して、Oracleに次のことを実行させます。
- ProcessedEventインデックスの完全なインデックススキャン
- イベントインデックスのフルインデックススキャン
- イベントテーブルのテーブルアクセス
- イベントテーブルをフィルタリングする
- 2つのセット間のアンチ結合
これは本当にばかげた私見です。
だから私の質問は:オラクルが早期のテーブルアクセスを主張する理由は何でしょうか?
追加:パフォーマンスが悪い。Event.IDのみを選択し、必要な行を「手動で」フェッチすることで、パフォーマンスの問題を修正しています。しかしもちろん、それは単なる回避策です。