2016-11-18 13 views
1

それぞれ6100万レコードを超える2つのテーブルを処理するクエリがあります。数百万行のクエリ処理のパフォーマンスチューニング

  • WB_YH_BCUPDATE_FULL_BASE:テーブル含む顧客や、彼らがアクティブになっていたすべての月。 (2014年から今まで)

CUSTOMERNUMBER | CAR MONTH


99999 | 201401
99999 | 201402
99999 | 201403
....

  • WB_YH_BCUPDATE_MATCH_MONTH:テーブル含む顧客とCAR_MONTH + 6ヶ月を含む架空の余分なフィールド+でアクティブであったすべての月。

CUSTOMERNUMBER | CAR_MONTH | MATCH_MONTH_6


99999 | | 201401 | 201407
99999 | 201402 | 201408
99999 | 201403 | 201409
...

今私は6ヶ月後(=彼らはテーブルに表示されます)、彼らはまだアクティブであった場合はすべての顧客とそれに対応するCAR_MONTHSのすべてをチェックしたいです。このために、作成したフィールドをMATCH_MONTH_6にする必要があります。

私は次のクエリを使用しています:

select distinct a.CUSTOMERNUMBER 
    , a.CAR_MONTH 
    , b.MATCH_MONTH_6 
    , CASE WHEN b.CUSTOMERNUMBER is null then 0 
      ELSE 1 
    END FL_MATCH_6   
from WB_YH_BCUPDATE_FULL_BASE a left join WB_YH_BCUPDATE_MATCH_MONTH b 
           on a.CUSTOMERNUMBER = b.CUSTOMERNUMBER  
           and a.CAR_MONTH = b.CAR_MONTH 
           and b.MATCH_MONTH_6 in (
           select CAR_MONTH 
           from WB_YH_BCUPDATE_FULL_BASE 
           where customernumber = a.customernumber 
           ); 

次実行計画から見ることができるように私のクエリのパフォーマンスが本当に悪い:

Plan Hash Value : 3376431373 

----------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation       | Name       | Rows  | Bytes  | Cost  | Time  | 
----------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT     |        | 25897713 | 673340538 | 371846479 | 02:56:04 | 
| 1 | HASH UNIQUE      |        | 25897713 | 673340538 | 371846479 | 02:56:04 | 
| 2 | NESTED LOOPS OUTER    |        | 61874441 | 1608735466 | 371674345 | 02:55:59 | 
| 3 |  TABLE ACCESS STORAGE FULL  | WB_YH_BCUPDATE_FULL_BASE  | 61874441 | 742493292 |  3225 | 00:00:01 | 
| 4 |  VIEW       |        |  1 |   14 |   6 | 00:00:01 | 
| 5 |  NESTED LOOPS     |        |  1 |   31 |   6 | 00:00:01 | 
| 6 |  NESTED LOOPS     |        |  24 |   31 |   6 | 00:00:01 | 
| * 7 |  TABLE ACCESS BY INDEX ROWID | WB_YH_BCUPDATE_MATCH_MONTH  |  1 |   19 |   3 | 00:00:01 | 
| * 8 |   INDEX RANGE SCAN   | WB_YH_BCUPDATE_MATCH_MONTH_IND |  24 |   |   2 | 00:00:01 | 
| * 9 |  INDEX RANGE SCAN   | WB_YH_BCUPDATE_FULL_BASE_IND |  24 |   |   2 | 00:00:01 | 
| * 10 |  TABLE ACCESS BY INDEX ROWID | WB_YH_BCUPDATE_FULL_BASE  |  1 |   12 |   3 | 00:00:01 | 
----------------------------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
------------------------------------------ 
* 7 - filter("A"."CAR_MONTH"="B"."CAR_MONTH") 
* 8 - access("A"."CUSTOMERNUMBER"="B"."CUSTOMERNUMBER") 
* 9 - access("CUSTOMERNUMBER"="A"."CUSTOMERNUMBER") 
* 10 - filter("CAR_MONTH"=TO_NUMBER("B"."MATCH_MONTH_6")) 

は君たちがどんな考えを持っていますかどのように私はこのクエリを最適化することができますか、または私はどのようにこのクエリをより効率的に書き換えることができますか?

敬具、

+0

テーブルにインデックスが必要です。 'join '条件は開始するのに適しています。 –

+0

したがって、 'WB_YH_BCUPDATE_MATCH_MONTH'には' WB_YH_BCUPDATE_FULL_BASE'と同じデータが含まれますが、追加の列が1つありますか? – SQB

+0

フィールドCUSTOMERNUMBERの両方のテーブルにインデックスがあります。そして@SQB;それは正しいですが、私は2つのテーブルにデータを複製せずに別の方法で結果を得ることはできませんでした。 – wbaeckelmans

答えて

2
SELECT 
    a.customernumber, 
    a.car_month, 
    b.car_month AS match_month_6, 
    CASE 
     WHEN b.customernumber IS NULL 
     THEN 0 
     END 1 
    END AS fl_match_6 
FROM WB_YH_BCUPDATE_MATCH_MONTH a 
LEFT JOIN WB_YH_BCUPDATE_MATCH_MONTH b 
    ON (a.customernumber = b.Customernumber AND a.match_month_6 = b.car_month); 

あなたはWB_YH_BCUPDATE_MATCH_MONTHWB_YH_BCUPDATE_FULL_BASEと同じデータが含まれていますが、1つの余分の列で、私たちはかつてのを使用し、後者を無視することができると言うので。

これで、それ自体が参加しました。もちろん、顧客番号だけでなく、日付に+ 6ヶ月を加算します。 6か月後に顧客がアクティブだった場合は、エントリが見つかります。もしそうでなければ、私たちはしません。

クエリの結果を完全に複製するには、元のクエリでも一致しなかった場合はNULLだったので、左の結合テーブルからmatch_month_6のデータを取得することを選択します。

両方の月フィールドにもインデックスを挿入する必要があります。これらのフィールドにも参加します。


お客様がその間に月間アクティブだったことを保証するものではありません。私は顧客が1月と7月に活動していましたが、このクエリによって返されます。

+0

ありがとう!クエリは、私が偉大なパフォーマンスで達成したいと思っているものを正確に行うようです。私は、これが顧客がその間に数ヶ月間アクティブだったことを分からないという事実を認識しています。このためのフィールドを作成することは、私が達成したい次のステップです。 :) – wbaeckelmans

+0

@ wbaeckelmansちょうど好奇心から、どのようなパフォーマンスの利得だった? – SQB

0
select w1.CUSTOMERNUMBER, w1.CAR_MONTH, nvl2(w2.CUSTOMERNUMBER, 'Yes', 'No') active_in_6_months 
    from WB_YH_BCUPDATE_FULL_BASE w1 
    left outer join WB_YH_BCUPDATE_MATCH_MONTH w2 
    on (w1.CUSTOMERNUMBER = w2. CUSTOMERNUMBER and w1.CAR_MONTH = w2.MATCH_MONTH_6); 

このクエリを使用すると、より優れた性能を有する所望の結果を与える必要があります。

+0

私はこのクエリを試してみましたが、パフォーマンスは素晴らしいですが、望みの結果が得られませんでした。私は6ヶ月後にはアクティブではないと言った特定の顧客を探しましたが、彼らは全期間中アクティブだったようです。 – wbaeckelmans

+0

これは、6ヶ月前に有効だった顧客を返します。同じアイデアだが、別の観点から。 – SQB

+0

@SQBあなたは正しい私はちょっと別の二人に参加する必要があります。私はあなたがすでに修正された質問を掲載しているのを見ます。 – Kacper

関連する問題