2016-11-18 54 views
1

我有一個查詢處理2個表,每個表有超過6100萬條記錄。處理數百萬行的查詢的性能調整

  • 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

你需要在表上索引。 「加入」條件是一個很好的起點。 –

+0

因此'WB_YH_BCUPDATE_MATCH_MONTH'包含與'WB_YH_BCUPDATE_FULL_BASE'相同的數據,但是隻有一列? – 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_MONTH包含相同的數據WB_YH_BCUPDATE_FULL_BASE,但有一個額外的列,我們可以用前者而忽略後者。

我們現在離開它自己。當然,在客戶號碼上,我們也加入日期+6個月的日期。如果客戶在6個月後活躍,我們會找到一個條目;如果沒有,我們不會。

要完全複製查詢結果,我們選擇從左連接表中獲取match_month_6的數據,因爲如果我們在原始查詢中無法獲得匹配項,則它爲NULL。

因爲我們也加入這兩個月份字段,所以你也應該在兩個月份字段上加上索引。


請注意,這並不能保證客戶在兩個月之間的活動。我的客戶在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