Oracle抗入実行計画問題
-
20-09-2019 - |
質問
いテーブルはこのように:
Event
id
type
... a bunch of other columns
ProcessedEvent
event_id
process
が指定義されて
- イベント(id)(PK)
- ProcessedEvent(event_id、プロセス)
最初のイベントを表すアプリケーション
第二は、この特定のイベントプロセスによる一定です。多くの工程を必要とする処理に一定のイベントも複数のエントリのテーブルの各エントリでは初めてとなります。
するためのすべてのイベントを必要とする処理を実施いたします以下のクエリ:
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指数
- フルインデックススキャンのイベント指数
- 抗加の
- テーブルにアクセスの
- フィルター
代わりにOracleは、以下の処理を行います
- フルインデックススキャンのProcessedEvent指数
- テーブル全体のスキャンのイベントテーブル
- フィルターのイベントテーブル
- 抗加のセット
ネットワークのヒントを取得しまOracleしなければならない。
- フルインデックススキャンのProcessedEvent指数
- フルインデックススキャンのイベント指数
- テーブルアクセスのイベントテーブル
- フィルターのイベントテーブル
- 抗加のセット
する場合には愚かなぁ.
このような中、私の質問は何であることを指摘できるがoracle主張の初期のテーブルにアクセス?
追加:の性能は悪いものです。を修正しましたので問題だけを選択し、イベントです。Idを取得し、必要な列を手動で'.もちろんそうです。
解決
あなたのFULL SCAN INDEXは、おそらく全表スキャンよりも高速になります。それでも、FULL SCAN INDEXは、完全なセグメントの読みであり、全表スキャンと同じ費用についてになります。
しかし、あなたはまた、ROWIDステップで表アクセスを追加しています。あなたはFULL TABLE SCANのために一つの論理IOのあたりのマルチブロックの(あなたのdb_file_multiblock_read_count parameter
に依存する)を取得するのに対し、一つの論理IOの行当たりのROWIDアクセスのための:それは高価なステップです。
結論として、オプティマイザはその計算します
cost(FULL TABLE SCAN) < cost(FULL INDEX SCAN) + cost(TABLE ACCESS BY ROWID)
の更新する:(INDEXイベントがどのようなタイプを知らないので)フルテーブルスキャンは、また、したがっての大きさを減少させる、より早く全索引スキャン経路におけるよりタイプにフィルタを可能に抗結合されますセット(FULL TABLE SCANのさらに別の利点)。
他のヒント
オプティマイザは、最初は意味がありません。多くのことを行いますが、それはそれはな理由のしています。彼らは、常にのの右ではないかもしれないが、彼らは理解している。
イベント・テーブルは、フルスキャンするのではなく、そのサイズのROWIDアクセスによって容易であろう。これはビットと作品を読み取るよりも、テーブル全体を順次読み出すため関与有意に少ないIO操作があることがあり得ます。
パフォーマンス悪いです、またはオプティマイザがそれをした理由はあなただけを求めている?
私は、オプティマイザの動作を説明することはできませんが、私の経験ではそうのように、MINUSとの代わりにそれを交換し、すべてのコストで「NOT IN」を避けるためにされています:
select * from Event
where id in (
select id from Event where type in ( 'typeA', 'typeB', 'typeC')
minus
select id from ProcessedEvent
)
私は、同様の変換を使用してクエリのパフォーマンスに桁違いを見てきました。
のような何かます:
WITH
PROCEEDED AS
(
SELECT
event_id
FROM
ProcessedEvent
WHERE
PROCESS = :1
)
SELECT
* // of course we do name the columns in the production code
FROM
EVENT
LEFT JOIN PROCEEDED P
ON
p.event_id = EVENT.event_id
WHERE
type IN ( 'typeA', 'typeB', 'typeC')
AND p.event_id IS NULL; -- exclude already proceeded
(少なくともはるかに速いNOT IN
よりも)十分に速く動作することができます。