このような実行速度の違いを得る唯一の方法は、(a)field4
にインデックスを付けることです。 、および(b)ロットがあります 空のデータブロックの;おそらく、直接経路の負荷を繰り返すことによって非常に高く設定された最高水準点からです。
最初のクエリは引き続きインデックスを使用し、期待どおりに実行されます。ただし、null値にはインデックスが付けられていないため、インデックスを使用してor field4 is null
であることを確認することはできません。 状態なので、全表スキャンにフォールバックします。
7000行の全表スキャンは長くはかからないので、それ自体はここでは問題にはなりません。しかし、それは とても時間がかかり、何か他のことが起こっています。全表スキャンでは、テーブルに割り当てられたすべてのデータブロックを調べて、行が含まれているかどうかを確認する必要があります。所要時間は、インラインCLOBストレージを使用している場合でも、7000行を保持するために必要なブロックよりもはるかに多くのブロックがあることを示しています。
大量の空のデータブロックを取得する最も簡単な方法は、大量のデータを取得してから、そのほとんどを削除することです。しかし、以前の質問に対する削除されたコメントで、以前はパフォーマンスは問題なく、悪化しているとおっしゃっていたと思います。これは、ダイレクトパス挿入<を実行した場合に発生する可能性があります。 / a> 特に、データを削除してからダイレクトパスモードで新しいデータを挿入することでデータを「更新」する場合。 /*+ append */
を持つ挿入でそれを行うことができます ヒント;または並行して;またはSQL*Loaderを介して。古い空のブロックは再利用されないため、そのたびに最高水準点が移動します。また、nullをチェックするクエリのパフォーマンスが少し低下するたびに。多くの反復の後、それは実際に合計し始めます。
データディクショナリをチェックして、テーブルに割り当てられているスペースの量を確認できます(user_segments
など)、それを実際に持っていると思うデータのサイズと比較します。テーブルを再構築することで、HWMをリセットできます。たとえば、次のようにします。
alter table mytable move;
(できればメンテナンスウィンドウで!)
デモとして、7000行を100回以上ダイレクトパス挿入および削除するサイクルを実行してから、両方のクエリを実行しました。最初のものは0.06秒かかりました(その多くはSQL Devleoperのオーバーヘッドです)。 2番目は1.260かかりました。 (私はまた、FTSを実行する必要があるため、同様の時間を取得したGordon'sを実行しました)。反復回数が増えると、違いはさらに顕著になりますが、スペースが足りなくなりました...次にalter table move
を実行しました 2番目のクエリを再実行しました。これには0.05秒かかりました。