2016-07-29 3 views
1

私は、このテーブル7000件のレコードnullをチェックするとこのクエリが遅くなるのはなぜですか?

を含む降順ARADMIN.V_PKGXMLCODE

Name     Null  Type   
--------------------- -------- ------------- 
REQUEST_ID   NOT NULL VARCHAR2(15) 
AVAILABILITY     VARCHAR2(69) 
XML_CODE      CLOB   
PACKAGENAME_UNIQUE    VARCHAR2(50) 
CATALOG      NUMBER(15)  
CHILD       VARCHAR2(255) 
CLASSIFICATION_SYSTEM   NUMBER(15)  
E_MAIL       VARCHAR2(69) 

は、クエリ

SELECT COUNT(*) FROM ARADMIN.V_PKGXMLCODE WHERE (CATALOG <> 0 AND CATALOG <> 2) AND (NOT (CHILD IS NULL)); 

は1秒未満かかりました。

クエリ

SELECT COUNT(*) FROM ARADMIN.V_PKGXMLCODE WHERE (CATALOG IS NULL OR (CATALOG <> 0 AND CATALOG <> 2)) AND (NOT (CHILD IS NULL)); 

は23秒かかります。

計画を説明するには、しかし、私は何ができる

enter image description here

...それは実際に素早く行くべきと主張しますか?

+0

最初のクエリでもフルテーブルスキャンを実行するのですか、または使用できるフィールド4にインデックスがありますか?そしてもしあれば、テーブルは繰り返し削除され(切り捨てられずに)、ダイレクトパスの挿入(すなわち '/ * + append * /'ヒント付き)で再生成されましたか? –

+1

最初のクエリの計画はどうですか? – nilsman

+0

NULL値にインデックスを付けることができないので、 'IS NULL'条件はインデックスを無視します。索引作成中にNULLABLE列とともに一定の値を使用することで、オプティマイザを確実に騙すことができます。しかし、あなたの質問の範囲内で答えるためには、私が前に述べたようにオプティマイザを騙さない限り、2回目のクエリは** FULL TABLE SCAN **になります。最初のクエリでインデックスを利用し、FTSを回避することができます。 1.第1クエリの説明計画も投稿してください。 2.最新の統計情報ですか? –

答えて

0

これは興味深いことです。 Oracleは良いオプティマイザを持っており、NULLで混同しないでください。

このバージョンのパフォーマンスはどうですか?

select x1.cnt + x2.cnt + x3.cnt 
from (select count(*) as cnt 
     from MYTABLE 
     where field4 = 1 and child is not null 
    ) x1 cross join 
    (select count(*) as cnt 
     from MYTABLE 
     where field4 = 4 and child is not null 
    ) x2 cross join 
    (select count(*) as cnt 
     from MYTABLE 
     where field4 is null and child is not null 
    ) x3; 

このバージョンでは、MYTABLE(field4, child)のインデックスを利用できます。

+0

x1 x2 x3とは何ですか? ORA-00904: "X3":無効な識別子ですか? – Thomas

+0

@Thomas - インラインビューのテーブルエイリアスです。彼らは 'x3.cnt'などでなければなりません。 –

+0

大丈夫です。それは23秒かかった。 – Thomas

3

このような実行速度の違いを得るには、(a)インデックスをfield4に設定し、(b)の空きデータブロックをにするだけです。おそらく高水準点から、繰り返しの直接経路負荷によって非常に高く設定されます。

最初のクエリでもインデックスが使用され、期待どおりに実行されます。しかし、NULL値は索引付けされないので、索引を使用してor field4 is nullの状態をチェックすることはできません。したがって、完全な表スキャンに戻ります。

それだけでは問題はありません。ここでは、7000行のフルテーブルスキャンに時間がかかりません。しかし、それはであるので、何かが続いています。フル・テーブル・スキャンでは、表に割り当てられたすべてのデータ・ブロックを調べて、行が含まれているかどうかを確認し、インラインCLOBストレージの場合でも7000行を保持する必要があるよりも多くのブロックがあることを示します。

多くの空のデータブロックを取得する最も簡単な方法は、大量のデータを保存してからそれを削除することです。しかし、私は以前の質問について今削除されたコメントでは、パフォーマンスは以前より良くなっていて、悪化していると言ったと思います。これは、direct-path insertsを実行した場合に発生します。特に、データを削除してダイレクトパスモードで新しいデータを挿入してデータをリフレッシュする場合に発生します。あなたは/*+ append */ヒントを持つインサートでこれを行うことができます。または並行して;またはSQL * Loaderを使用します。古い水っぽいブロックは再利用されないので、最高水準点が移動するたびに、ヌルをチェックするクエリのパフォーマンスが低下するたびに発生します。本当に足し算を重ねるくらいの反復の後に。

データディクショナリを確認して、テーブルに割り当てられている容量(user_segmentsなど)を確認し、実際に考えているデータのサイズと比較することができます。テーブルを再構築することによってHWMをリセットすることができます。行って、G:(!、好ましくは、メンテナンス・ウィンドウで)

alter table mytable move; 

私は、ダイレクト・パス・インサートにサイクルを走り、7000行に百回以上を削除し、その後、両方のクエリを実行したデモとして、 。最初のものは0.06秒かかりました(その大部分はSQL Devleoperのオーバーヘッドです)。第二は1.260を取った。 (私もGordon'sを走らせましたが、これはFTSをやっていなければならないので、同様の時間がありました)。反復回数が増えるにつれ、違いはさらに顕著になりましたが、スペースがなくなりました... alter table moveを実行して2回目のクエリを再実行してから0.05秒かかりました。

+0

私はARADMIN.V_PCKXMLCODEテーブルを変更することをお勧めします。 ? – Thomas

+0

また、他の方法で再構築してください。しかし、おそらく、人々がアクセスしている間にそれを行うべきではありません。私はそれが間違いなく最初に問題であることを示すクエリを考えようとしています、そして、私は 'user_segments'を見ているよりもうまくいきませんでした。ダイレクト・パス・ロードが実際に行われているかどうかを特定する必要もあります。もしそうなら、問題は徐々に戻ってくるでしょう。テーブルのデータはどのように維持されていますか?そしてその名前から...それは実際には見解ですか?はい、実際のテーブルはT111だと言われています - どうして*維持されていますか? –

+0

私は先に進み、ビューがアクセスしているテーブルでクエリを実行しました。まったく同じ結果。データがどのように維持されているかを調べようとしています。 – Thomas

関連する問題