1

このクエリを本番環境 (Oracle) で実行していますが、3 分以上かかります。実行時間を短縮する方法はありますか? svc_order とイベント テーブルの両方に、ほぼ 100 万のレコードが含まれています。

select 0 test_section, count(1) count, 'DD' test_section_value  
from svc_order so, event e  
where so.svc_order_id = e.svc_order_id  
  and so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')  
  and e.event_type = 230 and e.event_level = 'O'  
  and e.current_sched_date between 
      to_date( '09/01/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
      and to_date('09/29/2013 23:59:59', 'MM/DD/YYYY HH24:MI:SS')  
  and (((so.sots_ta = 'N') and (so.action_type = 0)) 
       or  ((so.sots_ta is null) and (so.action_type = 0)) 
       or  ((so.sots_ta = 'N') and (so.action_type is null)))
  and so.company_code = 'LL'
4

4 に答える 4

1

あなたが言ったことを見て、インデックスを作成することはできません。クエリがテーブルのフル テーブル スキャンを行っていることを願っています。パラレルヒントをお試しください。

select /*+ full(so) parallel(so, 4) */ 0 test_section, count(1) count, 'DD' test_section_value  
from svc_order so, event e  
where so.svc_order_id = e.svc_order_id  
  and so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')  
  and e.event_type = 230 and e.event_level = 'O'  
  and e.current_sched_date between 
      to_date( '09/01/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')
      and to_date('09/29/2013 23:59:59', 'MM/DD/YYYY HH24:MI:SS')  
  and (((so.sots_ta = 'N') and (so.action_type = 0)) 
       or  ((so.sots_ta is null) and (so.action_type = 0)) 
       or  ((so.sots_ta = 'N') and (so.action_type is null)))
  and so.company_code = 'LL'
于 2013-10-04T08:38:18.853 に答える
0

まず、統計が最新であることを確認します。

begin
    dbms_stats.gather_table_stats('[schema]', 'svc_order');
    dbms_stats.gather_table_stats('[schema]', 'event');
end;
/

このクエリは、2 つの小さなテーブル間の非常に単純な結合ですが、述語が複雑です。すべてを高速に実行するための魔法の構文を求めて、すべてのクエリを大幅に書き直したいとは思わないでしょう。はい、まれに がBETWEENうまく機能しない場合や、述語をインライン ビューに移動すると役立つ場合や、結合を に置き換えると役立つ場合INTERSECTがあります。しかし、それは私にはカーゴ・カルト・プログラミングのように聞こえます。これらの変更がなぜ違いを生むのか、自問してみてください。これらのタイプの変更によって常にパフォーマンスが向上するのであれば、なぜ Oracle はクエリを内部的に変換しないのでしょうか?

通常、オプティマイザーがより適切な決定を下せるように、より適切な情報をオプティマイザーに提供するようにしてください。通常、これはデフォルト設定で統計を収集するのと同じくらい簡単です。一部の述語は複雑すぎるため 、 などの動的サンプリング/*+ dynamic_sampling(6) */を使用するようにしてください。または、いくつかのヒストグラムを追加することもできます。または、次のような式統計を追加することもできます。

SELECT 
    DBMS_STATS.CREATE_EXTENDED_STATS(null,'SVC_ORDER',
        '(((so.sots_ta = 'N') and (so.action_type = 0)) 
        or  ((so.sots_ta is null) and (so.action_type = 0)) 
        or  ((so.sots_ta = 'N') and (so.action_type is null)))'
    ) 
FROM DUAL;
--Don't forget to re-gather statistics after this.

オプティマイザーはおそらく行数を過小評価しており、ハッシュ結合の代わりにネストされたループを使用しています。より多くの情報を提供した後、理想的にはハッシュ結合の使用を開始します。しかし、ある時点で、上記の方法とおそらく他の多くの機能を試した後、使用する結合の種類を指定できます。これは@Florin Ghitaの提案です/*+use_hash(so e)*/.

于 2013-10-02T18:17:48.120 に答える
0

追加のインデックスを持つことはできませんが、テーブルには少なくとも意味のある完全な主キーが必要です。これにより、少なくともインデックス、非/クラスター化、すべてが得られるはずです。それを見て、それを利用してみてください。

テーブルがヒープであり、そのまま処理したい場合は、それぞれの where フィルターを適用して各テーブルの行数を個別に減らし、その結果セットを結合する必要があります。クエリでは、完全な結果列がベーステーブルに依存することを意味するのは count(1) です。他の 2 つの列は定数です。JOIN/デカルト積なども….. DBエンジンがインデックスを探すようになるため、代わりにINTERSECTを使用してください。できるその他の変更: WHERE 条件列の右側で TO_DATE または任意の種類の関数を使用しないでください。ローカル変数でデータを準備し、クエリでローカル変数を使用します。また、BETWEEN よりも >= を使用してパフォーマンスが向上するかどうかを確認する必要がありますか?

クエリを変更し、冗長な where 条件を 1 つ組み合わせました。この変更が現在うまくいっているとしても、それが常にうまくいくとは限らないことに注意してください。あなたのテーブルがこれらのWHERE条件に適合するより多くのデータにヒットし始めると、これは再び遅いクエリとして戻ってきます。したがって、短期的にはこれでうまくいくかもしれませんが、長期的には代替オプションについて考える必要があります

    1)  for example Indexed Views on top of this tables
    2)  Create same tables with different name and sync data 
        between new and original table using  “Insert/Update/Delete Trigger”.




    SELECT COUNT(1) AS [COUNT], 'DD' test_section_value  ,0 test_section
    FROM
    (
        SELECT  so.svc_order_id
        FROM    svc_order so
        WHERE   so.entered_date >= to_date('01/01/2012', 'MM/DD/YYYY')
                AND so.company_code = 'LL'

        INTERSECT

        SELECT  e.svc_order_id
        FROM    event e
        WHERE   e.event_type = 230
                AND e.event_level = 'O'
                AND e.current_sched_date BETWEEN
                    to_date('09/01/2010 00:00:00','MM/DD/YYYY HH24:MI:SS')
                    AND to_date('09/29/2013 23:59:59','MM/DD/YYYY HH24:MI:SS')
                AND ( 
                        (( so.sots_ta = 'N' ) AND ( so.action_type IS NULL OR so.action_type = 0))
                        OR 
                        (( so.sots_ta IS NULL ) AND ( so.action_type = 0 )) 
                        --or ((so.sots_ta = 'N') and (so.action_type is null))
                    )
    )qry1
于 2013-10-02T13:49:29.200 に答える