sql >> データベース >  >> RDS >> Oracle

SQLクエリによる奇妙な速度の変化

    何が起こっているのかをよりよく理解するには、これを試してください:

    explain plan set statement_id = 'query1' for
    SELECT  count(ck.id)
    FROM    claim_key ck
    WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
         AND ck.clm_type = 5
         AND ck.prgrm_id = 1;
    

    そして:

    select *
    from table(dbms_xplan.display(statement_id=>'query1'));
    

    claim_keyにTABLEACCESSFULLを示す行が表示されると思います。

    次に試してください:

    explain plan set statement_id = 'query2' for
    SELECT  count(ck.id)
    FROM    claim_key ck
    WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
         AND ck.clm_type = 5;
    
    select *
    from table(dbms_xplan.display(statement_id=>'query2'));
    

    そして、それが(おそらく)どのインデックスを使用しているかを確認します。これにより、データベースが何をしているのかがわかり、理由を理解するのに役立ちます。 それをやっています。

    わかりました。説明プランを考えると、これは「インデックスが常に良いとは限らず、テーブルスキャンが常に悪いとは限らない」という典型的な例です。

    INDEX SKIP SCANは、インデックスの先頭の列が使用されていなくても、データベースがインデックスの使用を試みることができる場所です。基本的に、インデックスが次のようになっている場合(過度に単純化されている場合):

    COL1   COL2   ROWID
    A      X      1        <--
    A      Y      2
    A      Z      3
    B      X      4        <--
    B      Y      5
    B      Z      6 
    

    条件はWHEREcol2='X'でした。インデックススキップスキャンでは、COL1の各組み合わせを調べてcol2='X'の場所を探します。一致するもの(col1 =A、col2 =Xなど)が見つかると、値が変化する場所(col1 =B、次にcol1 =Cなど)までcol1の値を「スキップ」し、さらに一致するものを探します。

    キャッチは、インデックスが(一般的に!)次のように機能することです:1)値が見つかったインデックスで次のROWIDを見つける2)そのROWIDを持つテーブルブロックに移動する(TABLE ACCESS BY INDEX ROWID)3)一致するものがなくなるまで繰り返す見つかりました。

    (スキップスキャンの場合、次の値の変更が先頭の列のどこにあるかを見つけるためのコストも発生します。)

    これはすべて、少数の行には適切ですが、収穫逓減の法則に悩まされています。多数の行がある場合、それはそれほど素晴らしいことではありません。これは、インデックスブロック、テーブルブロック、インデックスブロック、テーブルブロックの順に読み取る必要があるためです(テーブルブロックが以前に読み取られた場合でも)。

    全表スキャンは、一部にはマルチブロック読み取りのおかげで、データを「耕す」だけです。データベースは1回の読み取りでディスクから多くのブロックを読み取ることができ、同じブロックを2回以上読み取ることはありません。

    INDEX FAST FULL SCANは、基本的にI_CLAIM_KEY_002をテーブルとして扱います。クエリに必要なものはすべて、インデックスだけで答えることができます。テーブルアクセスは必要ありません。 (I_CLAIM_KEY_002はclnt_id、dte_of_srvceとして定義されており、clnt_idまたはdte_of_srvceはnull許容ではないと思います。ck.idはnull以外の属性である必要があるため、ck.idのカウントはck.clnt_idのカウントと同じです。)

    したがって、最初のクエリについては、インデックスを再調整する場合を除いて、次のことを試してください。

    SELECT  /*+ FULL(ck) */ count(ck.id)
    FROM    claim_key ck
    WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
         AND ck.clm_type = 5
         AND ck.prgrm_id = 1
    

    これにより、claim_key(ck)で全表スキャンが強制され、他の2つと同様のパフォーマンスが見られます。 (これが、最初にクエリの前に「explain plan set statement_id ='query_hint' for」を付け、実行する前にdbms_xplanクエリを実行する場合であることを確認してください。)

    (ここで、「常にそのようなヒントを入力しますか?」と尋ねます。入力しないでください。これはテスト専用です。これは、FTSがINDEXSKIPSCANよりも優れているかどうかを確認するためだけのものです。 。そうである場合は、その理由を調べる必要があります。:)

    とにかく...私はそれがsneseになったと思います..私は意味があります。



    1. SpringデータJPAは1つの複合キーのみが自動インクリメントの問題です

    2. MYSQLは、各カテゴリから2つのランダムな行を選択します

    3. SPARSECOLUMNを使用する理由と時期(SQL SERVER 2008)

    4. データベース設計101:MySQLのパーティション