2016-11-18 64 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