SQL优化-利用with as的方式去掉nestloop连接

原语句:

select substr(i.disbdt, 1, 6),
       '20150228',
       nvl(sum(j.onlnbl), 0),
       nvl(sum(k.orgibl) - sum(k.onlnbl), 0) + nvl(sum(m.tranam), 0),
       nvl(sum(l1.onlnbl), 0),
       nvl(sum(l2.onlnbl), 0),
       nvl(sum(l3.onlnbl), 0),
       nvl(sum(l4.onlnbl), 0),
       nvl(sum(l6.onlnbl), 0),
       nvl(sum(l6.onlnbl), 0),
       nvl(sum(l7.onlnbl), 0),
       nvl(sum(l8.orgibl) - sum(l8.onlnbl), 0),
       nvl(sum(m.tranam), 0)
  from tmp_mtlncf h
  join srcapp.lnb_lncf i
    on h.lncfno = i.lncfno
  left join temp_cr_bl j
    on i.acctid = j.acctid
   and j.transt = '1'
  left join temp_cr_bl k
    on i.acctid = k.acctid
   and k.lnbltp in ('2', 'A')
  left join temp_cr_bl l1
    on i.acctid = l1.acctid
   and l1.transt = '1'
   and l1.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l1.inptdt between 1 and 30
  left join temp_cr_bl l2
    on i.acctid = l2.acctid
   and l2.transt = '1'
   and l2.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l2.inptdt between 31 and 60
  left join temp_cr_bl l3
    on i.acctid = l3.acctid
   and l3.transt = '1'
   and l3.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l3.inptdt between 61 and 90
  left join temp_cr_bl l4
    on i.acctid = l4.acctid
   and l4.transt = '1'
   and l4.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l4.inptdt between 91 and 120
  left join temp_cr_bl l5
    on i.acctid = l5.acctid
   and l5.transt = '1'
   and l5.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l5.inptdt between 121 and 150
  left join temp_cr_bl l6
    on i.acctid = l6.acctid
   and l6.transt = '1'
   and l6.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l6.inptdt between 151 and 180
  left join temp_cr_bl l7
    on i.acctid = l7.acctid
   and l7.transt = '1'
   and l7.lnbltp = '2'
   and To_Date('20150228', 'yyyymmdd') - l7.inptdt > 180
  left join temp_cr_bl l8
    on i.acctid = l8.acctid
   and l8.lnbltp in ('2', 'A')
   and l8.inptdt between
       to_date(substr('20150228', 1, 6) || '01', 'yyyymmdd') and
       to_date('20150228', 'yyyymmdd')
  left join temp_ad_tm m
    on i.acctid = m.acctid
 where i.disbdt between '20110901' and '20150228'
 group by substr(i.disbdt, 1, 6);

执行计划:

34	--------------------------------------------------------------------------------------------------------------
35	| Id  | Operation                               | Name       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
36	--------------------------------------------------------------------------------------------------------------
37	|   0 | SELECT STATEMENT                        |            |       |       |       |    48M(100)|          |
38	|   1 |  HASH GROUP BY                          |            |   339 | 91869 |       |    48M  (2)|188:31:53 |
39	|   2 |   NESTED LOOPS OUTER                    |            |  7228M|  1824G|       |    47M  (1)|186:29:46 |
40	|   3 |    NESTED LOOPS OUTER                   |            |   144M|    35G|       | 76533   (2)| 00:17:52 |
41	|   4 |     HASH JOIN RIGHT OUTER               |            | 66227 |    16M|       |  9871   (1)| 00:02:19 |
42	|   5 |      TABLE ACCESS FULL                  | TEMP_CR_BL | 46833 |   960K|       |  1701   (2)| 00:00:24 |
43	|   6 |      HASH JOIN RIGHT OUTER              |            | 66227 |    15M|       |  8168   (1)| 00:01:55 |
44	|   7 |       TABLE ACCESS FULL                 | TEMP_AD_TM |  2387 | 31031 |       |     4   (0)| 00:00:01 |
45	|   8 |       HASH JOIN RIGHT OUTER             |            | 66227 |    14M|       |  8163   (1)| 00:01:55 |
46	|   9 |        TABLE ACCESS BY INDEX ROWID      | TEMP_CR_BL |  1333 | 27993 |       |   447   (1)| 00:00:07 |
47	|  10 |         INDEX RANGE SCAN                | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
48	|  11 |        HASH JOIN RIGHT OUTER            |            | 66227 |    12M|       |  7716   (1)| 00:01:49 |
49	|  12 |         TABLE ACCESS BY INDEX ROWID     | TEMP_CR_BL |  1333 | 27993 |       |   447   (1)| 00:00:07 |
50	|  13 |          INDEX RANGE SCAN               | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
51	|  14 |         HASH JOIN RIGHT OUTER           |            | 66227 |    11M|       |  7268   (1)| 00:01:42 |
52	|  15 |          TABLE ACCESS BY INDEX ROWID    | TEMP_CR_BL |  1333 | 27993 |       |   447   (1)| 00:00:07 |
53	|  16 |           INDEX RANGE SCAN              | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
54	|  17 |          HASH JOIN OUTER                |            | 66227 |    10M|  3200K|  6821   (1)| 00:01:36 |
55	|  18 |           HASH JOIN RIGHT OUTER         |            | 20315 |  2955K|       |  4819   (1)| 00:01:08 |
56	|  19 |            TABLE ACCESS BY INDEX ROWID  | TEMP_CR_BL |  1333 | 27993 |       |   447   (1)| 00:00:07 |
57	|  20 |             INDEX RANGE SCAN            | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
58	|  21 |            HASH JOIN RIGHT OUTER        |            | 20315 |  2539K|       |  4371   (1)| 00:01:02 |
59	|  22 |             TABLE ACCESS BY INDEX ROWID | TEMP_CR_BL |  1333 | 25327 |       |   447   (1)| 00:00:07 |
60	|  23 |              INDEX RANGE SCAN           | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
61	|  24 |             HASH JOIN RIGHT OUTER       |            | 20315 |  2162K|       |  3924   (1)| 00:00:55 |
62	|  25 |              TABLE ACCESS BY INDEX ROWID| TEMP_CR_BL |  1333 | 27993 |       |   447   (1)| 00:00:07 |
63	|  26 |               INDEX RANGE SCAN          | IDX_INPTDT |  8000 |       |       |    12   (0)| 00:00:01 |
64	|  27 |              HASH JOIN                  |            | 20315 |  1745K|       |  3477   (1)| 00:00:49 |
65	|  28 |               TABLE ACCESS FULL         | TMP_MTLNCF | 20292 |   416K|       |    15   (0)| 00:00:01 |
66	|  29 |               TABLE ACCESS FULL         | LNB_LNCF   | 50284 |  3290K|       |  3460   (1)| 00:00:49 |
67	|  30 |           TABLE ACCESS FULL             | TEMP_CR_BL |   163K|  2078K|       |  1700   (2)| 00:00:24 |
68	|  31 |     VIEW                                |            |  2183 | 13098 |       |     1   (0)| 00:00:01 |
69	|  32 |      TABLE ACCESS FULL                  | TEMP_CR_BL |     5 |    85 |       |  1688   (1)| 00:00:24 |
70	|  33 |    VIEW                                 |            |    50 |   300 |       |     0   (0)|          |
71	|  34 |     TABLE ACCESS BY INDEX ROWID         | TEMP_CR_BL |     1 |    24 |       |   417   (1)| 00:00:06 |
72	|  35 |      INDEX RANGE SCAN                   | IDX_INPTDT |  7461 |       |       |    11   (0)| 00:00:01 |
73	--------------------------------------------------------------------------------------------------------------
分析说明: 我自己的判断,sql语句的效率瓶颈出现在执行计划中的nestloop部分,大量的嵌套循环导致逻辑读过高,这条sql一个小时的时间无法执行完成.
尝试了各种方法,包括使用hint的方式,都无法去掉nestlop,来走我所期望的hash join
最后一个个尝试,到底是在哪个临时表走了nestloop,发现是l8和k 表,  于是将l8表和k表使用with as 的方式,惊喜的发现走了hash join,然后执行该语句,两秒中出结果,心里倍加舒坦.
改后的sql:
with a as
 (select *
    from temp_cr_bl l8
   where  l8.lnbltp in ('2', 'A') and
    l8.inptdt between to_date('20150201', 'yyyymmdd') and
    to_date('20150228', 'yyyymmdd')),
   
   b as (
   select * from temp_cr_bl k where k.lnbltp in ('2', 'A')
   )

select substr(i.disbdt, 1, 6),
       '20150228',
       nvl(sum(j.onlnbl), 0),
        nvl(sum(k.orgibl) - sum(k.onlnbl), 0) + nvl(sum(m.tranam), 0),
       nvl(sum(l1.onlnbl), 0),
       nvl(sum(l2.onlnbl), 0),
       nvl(sum(l3.onlnbl), 0),
       nvl(sum(l4.onlnbl), 0),
       nvl(sum(l6.onlnbl), 0),
       nvl(sum(l6.onlnbl), 0),
       nvl(sum(l7.onlnbl), 0),
        nvl(sum(l8.orgibl) - sum(l8.onlnbl), 0),
       nvl(sum(m.tranam), 0)
  from srcapp.lnb_lncf i
  join tmp_mtlncf h
    on h.lncfno = i.lncfno
  left join temp_cr_bl j
    on i.acctid = j.acctid
   and j.transt = '1'
 left join b k
 on i.acctid = k.acctid
  left join temp_cr_bl l1
    on i.acctid = l1.acctid
   and l1.transt = '1'
   and l1.lnbltp = '2'
   and l1.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '1'
 day(3)
   and l1.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '30'
 day(3)
  left join temp_cr_bl l2
    on i.acctid = l2.acctid
   and l2.transt = '1'
   and l2.lnbltp = '2'
   and l2.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '31'
 day(3)
   and l2.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '60'
 day(3)
  left join temp_cr_bl l3
    on i.acctid = l3.acctid
   and l3.transt = '1'
   and l3.lnbltp = '2'
   and l3.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '61'
 day(3)
   and l3.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '90'
 day(3)
  left join temp_cr_bl l4
    on i.acctid = l4.acctid
   and l4.transt = '1'
   and l4.lnbltp = '2'
   and l4.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '91'
 day(3)
   and l4.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '120'
 day(3)
  left join temp_cr_bl l5
    on i.acctid = l5.acctid
   and l5.transt = '1'
   and l5.lnbltp = '2'
   and l5.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '121'
 day(3)
   and l5.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '150'
 day(3)
  left join temp_cr_bl l6
    on i.acctid = l6.acctid
   and l6.transt = '1'
   and l6.lnbltp = '2'
   and l6.inptdt <= To_Date('20150228', 'yyyymmdd') - interval '151'
 day(3)
   and l6.inptdt >= To_Date('20150228', 'yyyymmdd') - interval '180'
 day(3)
  left join temp_cr_bl l7
    on i.acctid = l7.acctid
   and l7.transt = '1'
   and l7.lnbltp = '2'
   and l7.inptdt < To_Date('20150228', 'yyyymmdd') - interval '180'
 day(3)
  left join a l8
 on i.acctid = l8.acctid
  left join temp_ad_tm m
    on i.acctid = m.acctid
 where i.disbdt between '20110901' and '20150228'
 group by substr(i.disbdt, 1, 6)


你可能感兴趣的:(ORACLE,SQL,调优)