2012-01-11 18 views
3

私はこのクエリを最適化しなければならないと言ってSQLクエリを与えられました。Oracleクエリーを最適化するにはどうすればよいですか?

私はaccross explain planになりました。だから、SQL開発者では、

のクエリを分割し、それぞれのコストを表示しました。

クエリを最適化するにはどうすればよいですか?私は何を探しますか?コストの高い要素ですか?

私は少しDBに新しいので、より多くの情報が必要な場合は、私に尋ねてください、私はそれを取得しようとします。

私は、クエリ自体を投稿して答えを得るのではなく、プロセスを理解しようとしています。

問題のクエリ:計画を説明し実行するには

SELECT cr.client_app_id, 
    cr.personal_flg, 
    r.requestor_type_id 
FROM credit_request cr, 
    requestor r, 
    evaluator e 
WHERE cr.evaluator_id = 96 AND 
    cr.request_id = r.request_id AND 
    cr.evaluator_id = e.evaluator_id AND 
    cr.request_id != 143462 AND 
    ((r.soc_sec_num_txt = 'xxxxxxxxx' AND   
    r.soc_sec_num_txt IS NOT NULL) OR 
    (lower(r.first_name_txt) = 'test' AND 
    lower(r.last_name_txt) = 'newprogram' AND 
    to_char(r.birth_dt, 'MM/DD/YYYY') = '01/02/1960' AND 
    r.last_name_txt IS NOT NULL AND 
    r.first_name_txt IS NOT NULL AND 
    r.birth_dt IS NOT NULL)) 

、私はスクリーンショットをアップロードしようとしています。クエリへの迅速な更新として

OPERATION OBJECT_NAME  OPTIONS  COST 
SELECT STATEMENT      15 
NESTED LOOPS    
NESTED LOOPS       15 
HASH JOIN        12 
Access Predicates 
CR.EVALUATOR_ID=E.EVALUATOR_ID 
INDEX EVALUATOR_PK  UNIQUE SCAN  0 
Access Predicates 
E.EVALUATOR_ID=96 
TABLE ACCESS CREDIT_REQUEST BY INDEX ROWID  11 
INDEX CRDRQ_DONE_EVAL_TASK_REQ_NDX  SKIP SCAN 10 
Access Predicates 
CR.EVALUATOR_ID=96 
Filter Predicates 
AND 
CR.EVALUATOR_ID=96 
CR.REQUEST_ID<>143462 
INDEX REQUESTOR_PK  RANGE SCAN  1 
Access Predicates 
CR.REQUEST_ID=R.REQUEST_ID 
Filter Predicates 
R.REQUEST_ID<>143462 
TABLE ACCESS REQUESTOR  BY INDEX ROWID  3 
Filter Predicates 
OR 
R.SOC_SEC_NUM_TXT='XXXXXXXX' 
AND 
R.BIRTH_DT IS NOT NULL 
R.LAST_NAME_TXT IS NOT NULL 
R.FIRST_NAME_TXT IS NOT NULL 
LOWER(R.FIRST_NAME_TXT)='test' 
LOWER(R.LAST_NAME_TXT)='newprogram' 
TO_CHAR(INTERNAL_FUNCTION(R.BIRTH_DT),'MM/DD/YYYY')='01/02/1960' 
+0

このプロセスを順を追って説明しますが、クエリを確認する必要があります。各問合せはそれぞれ異なりますが、一般に、表/クラスター索引スキャンはできるだけ避けたいとします。クエリプランを読むことは、科学よりも芸術です:) – Eric

+0

私はクエリで質問を更新しました – roymustang86

答えて

2

は、インデックス、そうエリックのポスト@からの次が来ます。where句では、evaluator_idに条件があり、クエリでclient_app_idpersonal_flgを選択します。したがって、おそらくcredit_requestのユニークなインデックスが(request_id, evaulator_id, client_app_id, personal_flgである必要があります。

選択した列をインデックスに入れると、by index rowidは表示されません。これは、インデックスから値を選択した後、テーブルを再入力して詳細情報を取得したことを意味します。この情報が既に索引に入っている場合、必要はありません。

evaluatorevaluator_idに参加しています(最初のインデックスに含まれています)。

requestor
これはrequest_idに上に接合されていると、あなたのwhere句はsoc_sec_num_textlower(first_name_txt)lower(last_name_txt)birth_dtが含まれます。可能な限り多くの条件に実際にインデックスを付ける必要があるため、可能であればユニークである必要があります。(request_id, soc_sec_num_text)のインデックスはこれ以上複雑です。 requestor_type_iudも選択しています。

この場合、多くの列を持つ機能インデックスを避けるために、(request_id, soc_sec_num_text, birth_dt)にインデックスを付けます。これにlower(first_name_txt)... etcを追加すると、列の選択度に応じて速度が向上する可能性があります。つまり、first_name_txtよりもはるかに多くの値がある場合は、birth_dtよりもbirth_dtの方が良いでしょう。したがって、一意でないインデックスの場合はクエリのスキャンが少なくなります。

このインデックスに選択した列を追加していないことに気が付きました。既に追加していないので、テーブルに入る必要があるためです。

evaluator
これはだけなので、あなたがこの列に一意、可能な場合は、インデックスを必要とするevaluator_idに参加しています。

3

、あなたはこのような何かにそれをリファクタリングしたいとしている:まず

SELECT 
    cr.client_app_id, 
    cr.personal_flg, 
    r.requestor_type_id 
FROM 
    credit_request cr 
    inner join requestor r on 
     cr.request_id = r.request_id 
    inner join evaluator e on 
     cr.evaluator_id = e.evaluator_id 
WHERE 
    cr.evaluator_id = 96 
    and cr.request_id != 143462 
    and (r.soc_sec_num_txt = 'xxxxxxxxx' 
     or (
      lower(r.first_name_txt) = 'test' 
      and lower(r.last_name_txt) = 'newprogram' 
      and r.birth_dt = date '1960-01-02' 
     ) 
    ) 

、カンマで参加することはあなたがしたい、クロス結合作成避ける。幸運なことに、Oracleは結合条件を指定してから内部結合としてそれを実行できるほどスマートですが、間違って何かを逃してしまわないように明示的にしたいと考えています。

第2に、is not nullのチェックは無意味です。列がnull=の場合、その行にはfalseが返されます。実際、null列と比較しても、null = nullでもfalseが返されます。 select 1 where null = nullselect 1 where null is nullでこれを試すことができます。 2番目のものだけが返されます。

第3に、日付をISOフォーマットと比較するのに十分なほどスマートです(少なくとも私が使用したのはそれ以前でした)。 r.birth_dt = date '1960-01-02'を実行して、その列で文字列フォーマットを実行しないでください。

言われているように、あなたの質問は、著しいパフォーマンスミスの点で正確に書かれていません。あなたが探したいのは指標です。 evaluatorevaluator_idに1つありますか? credit_requestはありますか?彼らはどのような種類ですか?通常、evaluatorはPK evaluator_idに1を持ち、credit_requestにはその列にも1が付きます。 requestorrequest_idの列も同じです。

その他の指標としては、フィルタリングするすべてのフィールドが考えられます。この場合、soc_sec_num_txt,first_name_txt,last_name_txt,birth_dt。後の3つの列に複数列のインデックスを配置し、soc_sec_num_txt列に単一の列インデックスを配置することを検討してください。

credit_request:あなたはrequest_idrequestorにこれに参加している
、私はユニークであると思いクエリをリファクタリングした後

+3

_ただあなたは 'r.birth_dt = '1960-01-02''_を実行できます。これはデフォルトで文字列を日付に変換することになりますNLS_DATA_FORMATにあります。したがって、動作するかどうかは、セッションごとに異なる設定に依存します。 'r.birth_dt = date '1960-01-02''や' to_date'のような 'date'キーワードを使った日付定数を' r.birth_dt = to_date(' 1960-01- 02 '、' YYYY-MM-DD ') ' –

+0

@ShannonSeverance - ありがとう!私がオラクルで働いて以来、しばらくしてきました。訂正を感謝します。私はその記事を編集した。今日は何かを学んだことがあります:) – Eric

+0

_通常、評価者はPKエバリュエーターIDでクラスタ化され、credit_requestは非クラスタ化されます._クラスタ化されたインデックスについて話していますか?もしそうなら、これはSQL Server用語です。 Oracleのクラスタ化された表は完全に異なり、**デフォルトではありません**と私の経験では典型的ではありません。 (正解が必要なネガも含めて編集しました) –

関連する問題