ITPub博客

首页 > 数据库 > Oracle > SQL优化案例-从执行计划定位SQL问题(三)

SQL优化案例-从执行计划定位SQL问题(三)

Oracle 作者:记录每一次错误 时间:2018-12-17 14:31:50 0 删除 编辑

当SQL出现问题,能从执行计划中快速的定位哪部分出现问题很重要,SQL文本如下(为保证客户隐私,已经将注释和文字部分去掉):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
SELECT   /*+  index (i IDX_INVM_BEC)*/ RQ,JGM,BZ,CUSTOMER_TYPE,
   B.CUSTOMER_NO,
   B.CUSTOMER_NAME  AS   DKHM,
   B.ACCT_NO DKZH,
   B.STATUS,
   B.LOAN_BAL,
   P,
   LX,
   NVL(( SELECT   A.ACCT_NO_DESC || A.ACCT_NO_ALL2 
          FROM   INVM_ZMQ A 
         WHERE   A.ACCT_NO=I.ACCT_NO 
           AND   A.ZHLB= '3' ),I.ACCT_NO)  AS   CKZH,
   I.CURR_VAL,
   ( CASE   WHEN   B.TRANSFER_ACCT=I.ACCT_NO  THEN   '嘻嘻嘻'   ELSE   ''   END )  AS   SM
FROM (
   SELECT   B.EXTDATE        AS   RQ,
          B.BRANCH_NO      AS   JGM,
          B.CURRENCY       AS   BZ,
          C.CUSTOMER_TYPE,
          B.CUSTOMER_NO,
          C.CUSTOMER_NAME,
          B.ACCT_NO,
          '啊啊'            AS   STATUS,
          B.LOAN_BAL,
          B.UNPD_PRIN_BAL  AS   P,
          ROUND(B.CAP_UNPD_INT,2)+
          ( CASE   WHEN   B.REPAY_SCHED  IN   ( 'M' , 'G' )  OR   L.REPAY_SCHED  IN   ( 'M' , 'G' )  THEN  
                ELSE   ( CASE   WHEN   L.PIA_CAPN_FREQ= 'S'   AND   L.PAST_DUE_CAPN_FREQ= 'S'  
                           THEN   ROUND(B.THEO_UNPD_ARR_PRN,2)
                                +( CASE   WHEN   L.FINE1_COMPD_OPT= 'Y'   THEN   ROUND(B.THEO_UNPD_ARRS_INT,2)  ELSE   0  END )
                                +( CASE   WHEN   L.FINE2_COMPD_OPT= 'Y'   THEN   ROUND(B.THEO_UNPD_INT_ARR,2)  ELSE   0  END )
                           ELSE  
                      END )
           END )  AS   LX,
           B.TRF_ACCT_NO  AS   TRANSFER_ACCT
     FROM   BORM PARTITION( "BORM_2018-06-13" ) B
    INNER   JOIN   LONP L  ON   L.ACCT_TYPE=B.ACCT_TYPE  AND   L.INT_CAT=B.INT_CAT
    INNER   JOIN   JGDY J  ON   B.BRANCH_NO = J.JGM  AND   (J.JGM= '1700'   OR   J.SJJGM= '1700' ) 
     LEFT   JOIN   CB_ACCT C  ON   B.ACCT_NO = C.ACCT_NO  AND   C.SYS_ID =  'BOR'
    WHERE   B.BAD_DEBT_IND  in   ( '02' , '52' ) 
      AND   B.STAT<> '40'
  ) B
LEFT   JOIN   INVM PARTITION( "INVM_2018-06-13" ) I 
     ON   B.CUSTOMER_NO=I.CUSTOMER_NO 
    AND   I.ACCT_DESC= 'S'  
    AND   I.CURR_VAL<>0 
    AND   I.BRANCH_NO  IN   ( SELECT   JGM  FROM   JGDY  WHERE   JGM= '1700'   OR   SJJGM= '1700' ) 
    AND   I.EXTDATE =  DATE '2018-06-13'  
    AND   I.CURR_STATUS= '00'  
WHERE   (B.P>0  OR   B.LX>0.01);

执行计划如下:

可以一眼定位到view部分导致整个执行缓慢,那么我们仔细分析下view部分是怎么执行的。INVM TABLE ACCESS BY LOCAL INDEX ROWID执行11分钟,总计13分钟执行完。

寻找view部分执行计划的入口,ID18和ID19做nested loop,返回结果17与21做NESTED LOOP,可以得知最先执行的是ID18,ID18走的iffs,且A-rows返回记录6256行数据,查看ID18谓词信息

18 - filter(("SJJGM"='1700' OR "JGM"='1700')) 从这部分再回到SQL文本寻找SQL代码是AND I.BRANCH_NO IN (SELECT JGM FROM JGDY WHERE JGM='1700' OR SJJGM='1700')也就是【SELECT JGM FROM JGDY WHERE JGM='1700' OR SJJGM='1700'】,难道这部分返回结果真的是6256行数据吗?带着疑问我查询了一下。

居然只返回了34行数据,为什么会这样子?

肯定是此处的JGDY_IDX3有什么问题,那么会有什么问题呢?往上看ID为8的JGDY_IDX3正确的返回了34行数据,又仔细看了下ID为18的JGDY_IDX3,starts184次,正好6256/184=34,那么原因找到了,正是因为ID4和ID15做NESTED LOOP,导致视图里面所有的部分都要多执行184次。按照上面的分析思路看ID4里面的执行计划都很正确,但是返回结果184行记录且ID4和ID15做nested loop,导致整个view部分缓慢。

那么就很好办了,ID4和ID15应该走hash join,查看outline data信息,还没办法使用db_name信息引导执行计划走hash join,那么只能改写SQL。

改写SQL如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
SELECT    RQ,JGM,BZ,CUSTOMER_TYPE,
   B.CUSTOMER_NO,
   B.CUSTOMER_NAME  AS   DKHM,
   B.ACCT_NO DKZH,
   B.STATUS,
   B.LOAN_BAL,
   P,
   LX,
   NVL(( SELECT   A.ACCT_NO_DESC || A.ACCT_NO_ALL2 
          FROM   INVM_ZMQ A 
         WHERE   A.ACCT_NO=C.ACCT_NO 
           AND   A.ZHLB= '3' ),C.ACCT_NO)  AS   CKZH,
   C.CURR_VAL,
   ( CASE   WHEN   B.TRANSFER_ACCT=C.ACCT_NO  THEN   '嘻嘻嘻'   ELSE   ''   END )  AS   SM
FROM (
   SELECT   B.EXTDATE        AS   RQ,
          B.BRANCH_NO      AS   JGM,
          B.CURRENCY       AS   BZ,
          C.CUSTOMER_TYPE,
          B.CUSTOMER_NO,
          C.CUSTOMER_NAME,
          B.ACCT_NO,
          '啊啊'            AS   STATUS,
          B.LOAN_BAL,
          B.UNPD_PRIN_BAL  AS   P,
          ROUND(B.CAP_UNPD_INT,2)+
          ( CASE   WHEN   B.REPAY_SCHED  IN   ( 'M' , 'G' )  OR   L.REPAY_SCHED  IN   ( 'M' , 'G' )  THEN  
                ELSE   ( CASE   WHEN   L.PIA_CAPN_FREQ= 'S'   AND   L.PAST_DUE_CAPN_FREQ= 'S'  
                           THEN   ROUND(B.THEO_UNPD_ARR_PRN,2)
                                +( CASE   WHEN   L.FINE1_COMPD_OPT= 'Y'   THEN   ROUND(B.THEO_UNPD_ARRS_INT,2)  ELSE   0  END )
                                +( CASE   WHEN   L.FINE2_COMPD_OPT= 'Y'   THEN   ROUND(B.THEO_UNPD_INT_ARR,2)  ELSE   0  END )
                           ELSE  
                      END )
           END )  AS   LX,
           B.TRF_ACCT_NO  AS   TRANSFER_ACCT
     FROM   BORM PARTITION( "BORM_2018-06-13" ) B
    INNER   JOIN   LONP L  ON   L.ACCT_TYPE=B.ACCT_TYPE  AND   L.INT_CAT=B.INT_CAT
    INNER   JOIN   JGDY J  ON   B.BRANCH_NO = J.JGM  AND   (J.JGM= '1700'   OR   J.SJJGM= '1700' ) 
     LEFT   JOIN   CB_ACCT C  ON   B.ACCT_NO = C.ACCT_NO  AND   C.SYS_ID =  'BOR'
    WHERE   B.BAD_DEBT_IND  in   ( '02' , '52' ) 
      AND   B.STAT<> '40'
  ) B
LEFT   JOIN   ( SELECT   /*+  index (I IDX_INVM_BEC) */ CUSTOMER_NO,ACCT_NO,CURR_VAL  FROM  
        INVM PARTITION( "INVM_2018-06-13" ) I 
INNER   JOIN   JGDY  ON   JGDY.JGM=I.BRANCH_NO  AND   (JGM= '1700'   OR   SJJGM= '1700' )
    AND   I.ACCT_DESC= 'S'  
    AND   I.CURR_VAL<>0 
    AND   I.EXTDATE =  DATE '2018-06-13'  
    AND   I.CURR_STATUS= '00' ) C   ON   B.CUSTOMER_NO=C.CUSTOMER_NO 
WHERE   (B.P>0  OR   B.LX>0.01);


改写完之后SQL由13分钟变为5秒钟执行完,看ID19还要执行999k次,查询ID18谓词信息对应SQL如下,确实是要返回999k行数据。

1
2
3
4
10:59:23 report.QData> SELECT   COUNT (*)  FROM   INVM PARTITION( "INVM_2018-06-13" ) I  WHERE   I.BRANCH_NO  IN   ( SELECT   JGM  FROM   JGDY  WHERE   JGM= '1700'   or   SJJGM= '1700' )   AND   I.EXTDATE=TO_DATE( ' 2018-06-13 00:00:00' ,  'syyyy-mm-dd hh24:mi:ss' )  AND   I.CURR_STATUS= '00' ;
COUNT (*)
----------
999424


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31547066/viewspace-2285449/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
性格开朗,有较强的学习能力,对oracle数据库的体系结构,搭建RAC,timesten,goldengate,分布式数据库,dataguard,系统调优有较深入的了解, 尤其是oracle优化,深入学习的主机命令,对数据库的优化,SQL语句的优化有深入的认识,目前正在shell脚本,mysql,以后会有计划学习大数据和python。

注册时间:2018-07-23

  • 博文量
    200
  • 访问量
    475047