• 资讯首页 > 数据库 >
  • Oracle某行系统SQL优化(案例五)

    Oracle某行系统SQL优化(案例五) 发布时间:2021-08-23 14:56 来源:ITPUB博客 阅读:0 作者: 栏目: 数据库 欢迎投稿:712375056

    问题说明:   

    业务人员反馈系统跑批慢了,平时耗时5分钟,现在需要跑3个多小时,而且是每月10日和每月15日都会变慢。

    环境说明:

    DB:Oracle 11.2.0.4.0 RAC
    OS:AIX 7.1

    问题分析:

    抓取跑批对应的慢SQL,查看SQL文本如下:

    select  '2021/08/15',
             RelativeDeductaccno,
             RelativeDeductaccno,
             LB.Deductaccno,
             lb.putoutno,
             LB.Customerid,
             LB.Customername,
             SI.ManageOrgID,
             0,
             LB.Normalbalance + LB.Overduebalance + LB.Waitoverduebalance AS balance,
             LB.Normalbalance + LB.Overduebalance + LB.Waitoverduebalance AS Actualbalance,
             SaveBeginSum * 10000,
             LoanBeginSum * 10000,
             SaveStandardSum * 10000,
             LoanStandardSum * 10000,
             nvl(ImpawnRatio1, 0),
             nvl(ImpawnRatio2, 0),
             nvl(ImpawnRatio3, 0),
             nvl(ImpawnRatio4, 0),
             IncomeBase * 10000,
             LB.Executerate / (30 * 1000),
             LB.Loanrate / (30 * 1000),
             case
               when LB.Executerate < LB.Loanrate then
                LB.Executerate / (30 * 1000)
               else
                LB.Loanrate / (30 * 1000)
             end,
             SI.SaveRate / 1000,
             LB.maturitydate,
             IncomeReturnDay,
             0,
             '0',
             '1',
             MainSaveToLoanFlag,
             case
               when LB.LoanStatus <= '1' then
                1
               else
                0
             end as LoanStatus,
             lb.assetflag,
             lb.businesstype,
             nvl(case
                   when cjc_fun_xxxxxxx(LB.putoutno, '2021/06/15') > 0 then
                    cjc_fun_xxxxxxx(LB.putoutno, '2021/06/15')
                   else
                    0
                 end,
                 0),
             case
               when nvl(LB.assetflag, 0) = '1' and
                    cjc_fun_xxxxxxx(LB.putoutno, '2021/06/15') > 0 then
                nvl(cjc_fun_xxxxxxx(LB.putoutno, '2021/06/15'), 0)
               else
                0
             end
        from cjcaaaaaaa_info SI, chen_balance LB
       where SI.putoutno = LB.putoutno
         and SI.Validdate <= '2021/08/15'
         and Status = '1'
         and ACCOUNTFLAG = '1'


    手动执行,查看速度:

    返回前100条记录很快,之后平均每10秒取出100行数据,最终取出全部结果集耗时很长。

    查看执行计划:

       PLAN_TABLE_OUTPUT
    ......
    20 
    21------------------------------------------------------------------------------------------------
    22| Id  | Operation                    | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
    23------------------------------------------------------------------------------------------------
    24|   0 | SELECT STATEMENT             |                 |       |       | 14354 (100)|          |
    25|   1 |  NESTED LOOPS                |                 |  6966 |  1367K| 14354   (1)| 00:00:01 |
    26|   2 |   NESTED LOOPS               |                 |  6966 |  1367K| 14354   (1)| 00:00:01 |
    27|*  3 |    TABLE ACCESS FULL         | cjcaaaaaaa_info |  6966 |   666K|   418   (1)| 00:00:01 |
    28|*  4 |    INDEX UNIQUE SCAN         | chen_balance_PK |     1 |       |     1   (0)| 00:00:01 |
    29|   5 |   TABLE ACCESS BY INDEX ROWID| chen_balance    |     1 |   103 |     2   (0)| 00:00:01 |
    30------------------------------------------------------------------------------------------------
    31 
    32Predicate Information (identified by operation id):
    33---------------------------------------------------
    34 
    35   3 - filter(("ACCOUNTFLAG"='1' AND "STATUS"='1' AND "SI"."VALIDDATE"<='2021/08/15'))
    36   4 - access("SI"."PUTOUTNO"="LB"."PUTOUTNO")
    37


    查看执行计划,可以看到,即使cjcaaaaaaa_info走了全表扫描,cost也很低,预估的时间也很短。

    难道是cjcaaaaaaa_info表统计信息不准确?

    检查后发现表统计信息是准确的,cjcaaaaaaa_info数据量很小。

    cjcaaaaaaa_info和chen_balance表关联关系很简单,where谓词条件也不复杂,那么是什么原因导致的SQL执行慢呢?

    显然当前的cjcaaaaaaa_info和chen_balance关联采用NESTED LOOPS已经是最优的,尝试添加hint强制hash join速度更慢了。

    既然表关联方式没问题,表访问路径没问题,还有可能哪块有问题呢?

    仔细检查了SQL,发现查询的列有一处 可疑的地方:

    ......
    nvl(case
                   when cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15') > 0 then
                    cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15')
                   else
                    0
                 end,
                 0),
             case
               when nvl(LB.assetflag, 0) = '1' and
                    cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15') > 0 then
                nvl(cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15'), 0)
    ......

    此处的cjc_fun_xxxxxxx看上去像是一个function,查看function的定义:

    select dbms_metadata.get_ddl('FUNCTION','cjc_fun_xxxxxxx','CHENJ3') from dual;

    函数部分由IF和ELSE两部分组成,每部分包含多个SELECT查询操作。

    那么SQL执行慢,是否和cjc_fun_xxxxxxx函数有关呢?

    注释掉原SQL中包含cjc_fun_xxxxxxx函数部分,再次执行SQL,速度恢复正常,不超过5分钟执行完成。

    单独进行函数部分测试:

    单独执行函数,速度很慢,每10秒返回100条记录

    select case
             when nvl(LB.assetflag, 0) = '1' and
                  cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15') > 0 then
              nvl(cjc_fun_xxxxxxx(LB.putoutno, '2021/08/15'), 0)
             else
              0
           end
      from cjcaaaaaaa_info SI, chen_balance LB
     where SI.putoutno = LB.putoutno
       and SI.Validdate <= '2021/08/15'
       and Status = '1'
       and ACCOUNTFLAG = '1'

    此时问题比较清晰了,就是因为cjc_fun_xxxxxxx函数部分导致SQL查询速度慢,那么为什么只有每月10号和每月15日速度慢呢?

    主要是因为原SQL包含case when部分,当每月10号和每月15日时,cjc_fun_xxxxxxx函数部分执行的次数更多。

    cjc_fun_xxxxxxx函数对性能究竟有多大的影响?

    在满足sAssetFlag = '1'条件时,函数会执行8条select语句,并将结果集进行加和后返回。

    在不满足sAssetFlag = '1'条件时,函数会执行14条select语句,并将结果集进行加和后返回。

    并且除了执行的select次数不同外,执行的select语句也是不一样的,也就是在sAssetFlag值不同时,即使执行相同次数cjc_fun_xxxxxxx函数,执行时间也不同。

      综合以上两点,SQL执行时间取决于函数执行次数,和单次函数执行的逻辑有关。

    例如:

    在最极端的情况下,查询的每条语句都会调用4次函数,每次函数执行14个select语句,在查询60000条数据时,后台实际会执行 336万条select语句。

    解决方案:

    和业务人员沟通,cjc_fun_xxxxxxx函数不能在优化了,但是可以使用中间表代替。
    例如,跑批前提前单独执行cjc_fun_xxxxxxx函数部分,并将结果插入到临时表t1中,
    在跑批时,不需要在执行cjc_fun_xxxxxxx函数,直接和临时表t1进行关联即可,
    经测试,速度有明显改善,平均耗时不超过5分钟。

    #####chenjuchao 2021-08-22 14:30#####


    免责声明:本站发布的内容(图片、视频和文字)以原创、来自本网站内容采集于网络互联网转载等其它媒体和分享为主,内容观点不代表本网站立场,如侵犯了原作者的版权,请告知一经查实,将立刻删除涉嫌侵权内容,联系我们QQ:712375056,同时欢迎投稿传递力量。