SQL优化-标量子查询的改写

原语句:

with d as
 (select *
    from dc.Dcam_Lbsq d
   where d.inptdt between
         to_date(substr('20110930', 1, 6) || '01', 'yyyymmdd') and
         to_date('20110930', 'yyyymmdd')
     and d.lnbltp in ('B', '5', '6')
     and d.Begndt <= To_Date('20110930', 'yyyymmdd')
     And d.Overdt > To_Date('20110930', 'yyyymmdd'))
select /*+index(c IDX_DCAM_LBSQ_ACCTID) index(d IDX_DCAM_LBSQ_ACCTID)*/
 a.lncfno as 账户号,
 a.loancn as 合同号,
 a.lncfno as 借据编号,
 null as 申请号,
 b.custno as 客户号,
 substr('20110930', 1, 6) as 年月戳,
 a.disbdt as 账户开户日期,
 a.closdt as 账户关闭日期,
 null as 还款频率,
 a.initam as 原始贷款金额,
 c.onlnbl + nvl(d.onlnbl, 0) as 本期贷款余额,
 c.orgibl as 本期应还本金,
 nvl(d.orgibl, 0) as 本期应还利息,
 c.orgibl - c.onlnbl as 本期实还本金,
 nvl(d.orgibl, 0) - nvl(d.onlnbl, 0) as 本期实还利息,
 null as 提前还款本金,
 case
   when a.matudt > '20110930' then
    0
   else
    c.onlnbl
 end as 逾期金额,
 case
   when a.matudt > '20110930' then
    0
   else
    c.onlnbl
 end as 本期逾期本金,
 nvl(d.onlnbl, 0) as 本期逾期利息,
 case
   when a.matudt > '20110930' then
    0
   else
    trunc(((to_date(a.matudt, 'yyyymmdd') - to_date('20110930', 'yyyymmdd')) - 1) / 30,
          0) + 1
 end as 本期逾期期数,
 case
   when a.matudt > '20110930' then
    0
   else
    to_date('20110930', 'yyyymmdd') - to_date(a.matudt, 'yyyymmdd')
 end as 本期最大逾期天数,
 case
   when a.matudt > '20110930' then
    0
   else
    to_date('20110930', 'yyyymmdd') - to_date(a.matudt, 'yyyymmdd')
 end as 逾期天数,
 null as 贷款剩余期数,
 null as 贷款期数,
 (select nvl(sum(i.tranam), 0)
    from dc.Dcam_Lscf h
    join dc.Dcam_Bspg i
      on h.contno = i.contno
   where h.lncfno = a.lncfno) as 抵质押物认定价值
  from srcapp.lnb_lncf a
  join srcapp.knc_acid b
    on a.lncfno = b.datavl
--join mon_day j on a.disbdt < '20110930'
  join dc.Dcam_Lbsq c
    on a.acctid = c.acctid
   and c.lnbltp in ('1', '2')
   and c.Begndt <= To_Date('20110930', 'yyyymmdd')
   And c.Overdt > To_Date('20110930', 'yyyymmdd')
  left join d
  on a.acctid = d.acctid
 where a.retnfs = '1'
   and a.disbdt < '20110930'
   and a.initam <= 5000000
执行计划:(DCAM_LBSQ有四千多万的数据,KNC_ACID表有一千三百多万的数据,LNB_LNCF 有三十多万的数据   )

13	--------------------------------------------------------------------------------------------------------------------------------------
14	| Id  | Operation                             | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
15	--------------------------------------------------------------------------------------------------------------------------------------
16	|   0 | SELECT STATEMENT                      |                      |       |       |       |  3189K(100)|          |       |       |
17	|   1 |  SORT AGGREGATE                       |                      |     1 |    51 |       |            |          |       |       |
18	|*  2 |   HASH JOIN                           |                      |     1 |    51 |       |  3197   (2)| 00:00:45 |       |       |
19	|*  3 |    TABLE ACCESS FULL                  | DCAM_LSCF            |     1 |    28 |       |  2945   (2)| 00:00:42 |       |       |
20	|   4 |    TABLE ACCESS FULL                  | DCAM_BSPG            | 51086 |  1147K|       |   252   (1)| 00:00:04 |       |       |
21	|*  5 |  HASH JOIN                            |                      |  2101K|   523M|    79M|  3189K  (1)| 12:24:19 |       |       |
22	|*  6 |   HASH JOIN RIGHT OUTER               |                      |   357K|    75M|  4544K|  2244K  (1)| 08:43:44 |       |       |
23	|   7 |    PARTITION RANGE ITERATOR           |                      | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |     1 |    10 |
24	|   8 |     VIEW                              |                      | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |       |       |
25	|*  9 |      TABLE ACCESS BY LOCAL INDEX ROWID| DCAM_LBSQ            | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |     1 |    10 |
26	|* 10 |       INDEX RANGE SCAN                | IDX_DCAM_LBSQ_ACCTID |  1630K|       |       | 61415   (1)| 00:14:20 |     1 |    10 |
27	|* 11 |    HASH JOIN                          |                      |   357K|    58M|    51M| 44239   (1)| 00:10:20 |       |       |
28	|* 12 |     TABLE ACCESS FULL                 | LNB_LNCF             |   356K|    47M|       |  3481   (2)| 00:00:49 |       |       |
29	|  13 |     TABLE ACCESS FULL                 | KNC_ACID             |    13M|   435M|       | 13062   (2)| 00:03:03 |       |       |
30	|  14 |   PARTITION RANGE ITERATOR            |                      |  2097K|    80M|       |   937K  (1)| 03:38:45 |     1 |    10 |
31	|  15 |    TABLE ACCESS BY LOCAL INDEX ROWID  | DCAM_LBSQ            |  2097K|    80M|       |   937K  (1)| 03:38:45 |     1 |    10 |
32	|* 16 |     INDEX RANGE SCAN                  | IDX_DCAM_LBSQ_ACCTID |   668K|       |       | 61383   (1)| 00:14:20 |     1 |    10 |
33	--------------------------------------------------------------------------------------------------------------------------------------
34	 
35	Predicate Information (identified by operation id):
36	---------------------------------------------------
37	 
38	   2 - access("H"."CONTNO"="I"."CONTNO")
39	   3 - filter(("H"."CONTNO" IS NOT NULL AND "H"."LNCFNO"=:B1))
40	   5 - access("A"."ACCTID"="C"."ACCTID")
41	   6 - access("A"."ACCTID"="D"."ACCTID")
42	   9 - filter(("D"."INPTDT"<=TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "D"."INPTDT">=TO_DATE(' 2011-09-01 
43	              00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
44	  10 - access("D"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "D"."BEGNDT"<=TO_DATE(' 2011-09-30 
45	              00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
46	       filter(("D"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND INTERNAL_FUNCTION("D"."LNBLTP")))
47	  11 - access("A"."LNCFNO"="B"."DATAVL")
48	  12 - filter(("A"."INITAM"<=5000000 AND "A"."DISBDT"<'20110930' AND "A"."RETNFS"='1'))
49	  16 - access("C"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "C"."BEGNDT"<=TO_DATE(' 2011-09-30 
50	              00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
51	       filter(("C"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND INTERNAL_FUNCTION("C"."LNBLTP")))
52	 
分析说明: 之前还没有使用with as的形式,直接select,根本查不出来数据,使用with as后大概5分钟可以弹出100条数据,但结果集将近30万的数据,预计要5个小时左右才能完全查出结果,速度慢的令人发指.

仔细观察执行计划后,对于大表都走了hash join,但最上面的标量子查询不是如此,于是怀疑性能问题出现在标量子查询部分.

对于标量子查询,如果where谓词条件后面的结果集很少,那么性能没有什么问题,但当where后面结果集很大,比如几十万的数据,那么表量子查询的性能将会很差,这时候考虑将标量子查询改为left join的方式,
让原有的标量子查询中的表 参与表连接.

修改成如下写法后,40秒左右完成查询.
with d as
 (select *
    from dc.Dcam_Lbsq d
   where d.inptdt between
         to_date(substr('20110930', 1, 6) || '01', 'yyyymmdd') and
         to_date('20110930', 'yyyymmdd')
     and d.lnbltp in ('B', '5', '6')
     and d.Begndt <= To_Date('20110930', 'yyyymmdd')
     And d.Overdt > To_Date('20110930', 'yyyymmdd'))
select /*+index(c IDX_DCAM_LBSQ_ACCTID) index(d IDX_DCAM_LBSQ_ACCTID)*/
 a.lncfno as 账户号,
 a.loancn as 合同号,
 a.lncfno as 借据编号,
 null as 申请号,
 b.custno as 客户号,
 substr('20110930', 1, 6) as 年月戳,
 a.disbdt as 账户开户日期,
 a.closdt as 账户关闭日期,
 null as 还款频率,
 a.initam as 原始贷款金额,
 c.onlnbl + nvl(d.onlnbl, 0) as 本期贷款余额,
 c.orgibl as 本期应还本金,
 nvl(d.orgibl, 0) as 本期应还利息,
 c.orgibl - c.onlnbl as 本期实还本金,
 nvl(d.orgibl, 0) - nvl(d.onlnbl, 0) as 本期实还利息,
 null as 提前还款本金,
 case
   when a.matudt > '20110930' then
    0
   else
    c.onlnbl
 end as 逾期金额,
 case
   when a.matudt > '20110930' then
    0
   else
    c.onlnbl
 end as 本期逾期本金,
 nvl(d.onlnbl, 0) as 本期逾期利息,
 case
   when a.matudt > '20110930' then
    0
   else
    trunc(((to_date(a.matudt, 'yyyymmdd') - to_date('20110930', 'yyyymmdd')) - 1) / 30,
          0) + 1
 end as 本期逾期期数,
 case
   when a.matudt > '20110930' then
    0
   else
    to_date('20110930', 'yyyymmdd') - to_date(a.matudt, 'yyyymmdd')
 end as 本期最大逾期天数,
 case
   when a.matudt > '20110930' then
    0
   else
    to_date('20110930', 'yyyymmdd') - to_date(a.matudt, 'yyyymmdd')
 end as 逾期天数,
 null as 贷款剩余期数,
 null as 贷款期数,
  抵质押物认定价值
  from srcapp.lnb_lncf a
  join srcapp.knc_acid b
    on a.lncfno = b.datavl
--join mon_day j on a.disbdt < '20110930'
  join dc.Dcam_Lbsq c
    on a.acctid = c.acctid
   and c.lnbltp in ('1', '2')
   and c.Begndt <= To_Date('20110930', 'yyyymmdd')
   And c.Overdt > To_Date('20110930', 'yyyymmdd')
  left join d
  on a.acctid = d.acctid
  left join (select h.lncfno,nvl(sum(i.tranam), 0) as 抵质押物认定价值
    from dc.Dcam_Lscf h
    join dc.Dcam_Bspg i
      on h.contno = i.contno
      group by h.lncfno) s
   on a.lncfno = s.lncfno
 where a.retnfs = '1'
   and a.disbdt < '20110930'
   and a.initam <= 5000000
新的执行计划:  这样看了,这条执行计划是多么的优美...咳咳.

13	---------------------------------------------------------------------------------------------------------------------------------------
14	| Id  | Operation                              | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
15	---------------------------------------------------------------------------------------------------------------------------------------
16	|   0 | SELECT STATEMENT                       |                      |       |       |       |  3198K(100)|          |       |       |
17	|*  1 |  HASH JOIN                             |                      |  2101K|   713M|   104M|  3198K  (1)| 12:26:26 |       |       |
18	|   2 |   PARTITION RANGE ITERATOR             |                      |  2097K|    80M|       |   937K  (1)| 03:38:45 |     1 |    10 |
19	|   3 |    TABLE ACCESS BY LOCAL INDEX ROWID   | DCAM_LBSQ            |  2097K|    80M|       |   937K  (1)| 03:38:45 |     1 |    10 |
20	|*  4 |     INDEX RANGE SCAN                   | IDX_DCAM_LBSQ_ACCTID |   668K|       |       | 61383   (1)| 00:14:20 |     1 |    10 |
21	|*  5 |   HASH JOIN RIGHT OUTER                |                      |   357K|   107M|  8944K|  2252K  (1)| 08:45:32 |       |       |
22	|   6 |    VIEW                                |                      | 85512 |  7933K|       |  3881   (2)| 00:00:55 |       |       |
23	|   7 |     HASH GROUP BY                      |                      | 85512 |  4258K|     9M|  3881   (2)| 00:00:55 |       |       |
24	|*  8 |      HASH JOIN                         |                      | 85512 |  4258K|       |  3198   (2)| 00:00:45 |       |       |
25	|   9 |       TABLE ACCESS FULL                | DCAM_BSPG            | 51086 |  1147K|       |   252   (1)| 00:00:04 |       |       |
26	|* 10 |       TABLE ACCESS FULL                | DCAM_LSCF            | 86603 |  2368K|       |  2944   (2)| 00:00:42 |       |       |
27	|* 11 |    HASH JOIN RIGHT OUTER               |                      |   357K|    75M|  4544K|  2244K  (1)| 08:43:44 |       |       |
28	|  12 |     PARTITION RANGE ITERATOR           |                      | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |     1 |    10 |
29	|  13 |      VIEW                              |                      | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |       |       |
30	|* 14 |       TABLE ACCESS BY LOCAL INDEX ROWID| DCAM_LBSQ            | 77288 |  3622K|       |  2197K  (1)| 08:32:45 |     1 |    10 |
31	|* 15 |        INDEX RANGE SCAN                | IDX_DCAM_LBSQ_ACCTID |  1630K|       |       | 61415   (1)| 00:14:20 |     1 |    10 |
32	|* 16 |     HASH JOIN                          |                      |   357K|    58M|    51M| 44239   (1)| 00:10:20 |       |       |
33	|* 17 |      TABLE ACCESS FULL                 | LNB_LNCF             |   356K|    47M|       |  3481   (2)| 00:00:49 |       |       |
34	|  18 |      TABLE ACCESS FULL                 | KNC_ACID             |    13M|   435M|       | 13062   (2)| 00:03:03 |       |       |
35	---------------------------------------------------------------------------------------------------------------------------------------
36	 
37	Predicate Information (identified by operation id):
38	---------------------------------------------------
39	 
40	   1 - access("A"."ACCTID"="C"."ACCTID")
41	   4 - access("C"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "C"."BEGNDT"<=TO_DATE(' 2011-09-30 
42	              00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
43	       filter(("C"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND INTERNAL_FUNCTION("C"."LNBLTP")))
44	   5 - access("A"."LNCFNO"="S"."LNCFNO")
45	   8 - access("H"."CONTNO"="I"."CONTNO")
46	  10 - filter("H"."CONTNO" IS NOT NULL)
47	  11 - access("A"."ACCTID"="D"."ACCTID")
48	  14 - filter(("D"."INPTDT"<=TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "D"."INPTDT">=TO_DATE(' 2011-09-01 
49	              00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
50	  15 - access("D"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "D"."BEGNDT"<=TO_DATE(' 2011-09-30 
51	              00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
52	       filter(("D"."OVERDT">TO_DATE(' 2011-09-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND INTERNAL_FUNCTION("D"."LNBLTP")))
53	  16 - access("A"."LNCFNO"="B"."DATAVL")
54	  17 - filter(("A"."INITAM"<=5000000 AND "A"."DISBDT"<'20110930' AND "A"."RETNFS"='1'))




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值