优化案例2:select标量子查询且主查询排序


DM技术交流QQ群:940124259

1. 场景描述

华南服务中心的同事微信群上发出一条查询SQL,称带上排序操作执行很慢,需要近8秒的时间返回结果集。
意思比较明确,带上排序才会这么慢的,看似缩小排查范围,仅凭是否存在排序操作判定问题,难免会让人走进死胡同。
幸亏当时SQL不是很复杂,凭借达梦现在的工具ET和执行计划,结合平时的经验推测和技术手段,7分钟远程,准确定位真实的瓶颈点,
将该SQL优化到100毫秒,使同事拍手称赞。


2. 分析过程

2.1 查看原始SQL执行计划

explain
SELECT
        a.fwid                                         ,
        a.ldid                                         ,
        a.mpid                                         ,
        a.MYCH                                         ,
        a.CH                                           ,
        a.fwh                                          ,
        a.th                                           ,
        a.fh                                           ,
        a.dh                                           ,
        a.fwlx                                         ,
        c.fwgn                                         ,
        c.fwgn fwgncode                                ,
        c.jtgn                                         ,
        b.cg                                           ,
        b.fwhx                                         ,
        a.dz                                           ,
        a.mp                                           ,
        a.ZJZMJ as zmj                                 ,
        a.TNMJ                                         ,
        a.GTMJ                                         ,
        b.fbyt                                         ,
        b.FFBYT                                        ,
        b.cf                                           ,
        b.wsj                                          ,
        b.dq                                           ,
        b.xq                                           ,
        b.nq                                           ,
        b.bq                                           ,
        c.HTAH                                         ,
        c.yzzt                                         ,
        c.QQAH                                         ,
        c.QQZT                                         ,
        REPLACE(a.ch, '夹', '') pxch                    ,
        nvl(c.zyzlzt, 0) zyzlzt                        ,
        a.jzjg                                         ,
        c.djzt                                         ,
        c.htzt                                         ,
        a.jlzt                                         ,
        decode(c.sfhq, '0', '0', '1', '1', '0')sfhq    ,
        decode(c.sfzy, '0', '0', '1', '1', '0')sfzy    ,
        decode(c.sfgjpt, '0', '0', '1', '1', '0')sfgjpt,
        decode(c.sfxjf, '0', '0', '1', '1', '0')sfxjf  ,
        c.xzzt                                         ,
        c.yyzt                                         ,
        c.dyzt                                         ,
        c.sfzg sfzg                                    ,
        mp.dz mpdz                                     ,
        c.sffc                                         ,
        a.jjmj                                         ,
        c.fwyt                                         ,
        a.xzqh xzqh_code                               ,
        a.beiz                                         ,
        a.fcgbz                                        ,
        c.sfbj                                         ,
        c.gjptfl                                       ,
        a.YSZJZMJ                                      ,
        a.YSTNMJ                                       ,
        a.YSGTMJ                                       ,
        c.djah fwb_djah                                ,
        c.JZMJDJ                                       ,
        c.TNMJDJ                                       ,
        a.chbdcdyh                                     ,
        a.chah                                         ,
        a.sfxgchmj                                     ,
        c.JCYFWZT                                      ,
        c.hbfgsdzt                                     ,
        nvl(c.islock, 0) islock                        ,
        c.hqlx hqlx                                    ,
        c.DJAH DJAH                                    ,
        a.xzqh xzqh                                    ,
        C.SFJGBA SFJGBA                                ,
        C.SFCWBA SFCWBA                                ,
        (
                select
                        decode(c.sfcwba, '1', decode(max(cw.balx), '1', '出售(1:1)', '3', '整体转让', '出售(大于1:1)'), '')
                from
                        T_CWZS_CWZSAJB cw,
                        T_CWZS_CWAJB aj
                where
                        cw.ajxxid   =aj.ajxxid
                    and aj.fwid     = a.fwid
                    and cw.del_flag = '0'
                    and aj.del_flag ='0'
                    and cw.jlzt     = '1'
        )
        Sblx         ,
        a.kfsid kfsid,
        c.sfgycq sfgycq
FROM
        T_XMGK_FWFSB b,
        T_XMGK_MPB mp ,
        T_XMGK_FWZTB c,
        T_XMGK_FWB a
left join T_XMGK_FCFFWGXB fcf
on
        fcf.FWID     = a.FWID
    and fcf.del_flag = '0'
WHERE
        a.FWID      = b.FWID
    and b.FWID      = c.FWID
    and a.mpid      =mp.mpid
    and b.del_flag  = '0'
    and a.del_flag  = '0'
    and c.del_flag  = '0'
    and mp.del_flag = '0'
    and a.mpid      = '112'
    and c.hqlx     <> '2'
Order By
        CAST(regexp_replace(a.ch, '([0-9]-[0-9])|[^-0-9.]') as  int),
        CAST(regexp_replace(a.fwh, '([0-9]-[0-9])|[^-0-9.]') as int);


-- 执行计划
/*
1   #NSET2: [169, 1, 3408] 
2     #PIPE2: [169, 1, 3408] 
3       #PIPE2: [168, 1, 3408] 
4         #PRJT2: [2, 1, 3408]; exp_num(75), is_atom(FALSE) 
5           #SORT3: [2, 1, 3408]; key_num(2), is_distinct(FALSE), top_flag(0), is_adaptive(0)
6             #HEAP TABLE SCAN: [1, 1, 3408]; table_no(0), 
7         #SPL2: [166, 1, 3760]; key_num(2), spool_num(0), is_atom(FALSE), has_variable(0) 
8           #PRJT2: [166, 1, 3760]; exp_num(3), is_atom(FALSE) 
9             #HAGR2: [166, 1, 3760]; grp_num(1), sfun_num(5); slave_empty(0) keys(DMTEMPVIEW_16784484.AUTOID) 
10              #NEST LOOP LEFT JOIN2: [164, 1, 3760]; join condition(AJ.FWID = DMTEMPVIEW_16784484.ORDER_COL2)[with var] partition_keys_num(0) ret_null(0)
11                #HEAP TABLE SCAN: [1, 1, 3408]; table_no(0), 
12                #HASH2 INNER JOIN: [81, 1, 352];  KEY_NUM(1); KEY(AJ.AJXXID=CW.AJXXID) KEY_NULL_EQU(0)
13                  #SLCT2: [80, 1, 152]; (AJ.DEL_FLAG = '0' AND AJ.FWID = var1)
14                    #CSCN2: [80, 550864, 152]; INDEX33569077(T_CWZS_CWAJB as AJ) -- 数据量有点大
15                  #SLCT2: [1, 1306, 200]; (CW.DEL_FLAG = '0' AND CW.JLZT = '1')
16                    #CSCN2: [1, 2516, 200]; INDEX33569078(T_CWZS_CWZSAJB as CW)
17      #HEAP TABLE: [1, 1, 3408]; table_no(0) full(FALSE), mpp_full(0) autoid(TRUE)
18        #PRJT2: [1, 1, 3408]; exp_num(72), is_atom(FALSE) 
19          #INDEX JOIN LEFT JOIN2: [1, 1, 3408] join condition(FCF.DEL_FLAG = '0') ret_null(0)
20            #SLCT2: [1, 1, 3408]; (C.DEL_FLAG = '0' AND C.HQLX <> '2' AND A.FWID = C.FWID)
21              #NEST LOOP INDEX JOIN2: [1, 1, 3408] 
22                #SLCT2: [1, 1, 1914]; B.DEL_FLAG = '0'
23                  #NEST LOOP INDEX JOIN2: [1, 1, 1914] 
24                    #MERGE INNER JOIN3: [1, 1, 1410]; KEY_NUM(1); KEY(COL_4 = COL_1) KEY_NULL_EQU(0)
25                      #SLCT2: [1, 21, 1266]; A.DEL_FLAG = '0'
26                        #BLKUP2: [1, 22, 1266]; INDEX_XMGK_FWB_MPID(A)
27                          #SSEK2: [1, 22, 1266]; scan_type(ASC), INDEX_XMGK_FWB_MPID(T_XMGK_FWB as A), scan_range['112','112']
28                      #SLCT2: [1, 1, 144]; MP.DEL_FLAG = '0'
29                        #CSEK2: [1, 1, 144]; scan_type(UNIQUE), INDEX33568939(T_XMGK_MPB as MP), scan_range['112','112']
30                    #CSEK2: [1, 1, 0]; scan_type(UNIQUE), INDEX33568938(T_XMGK_FWFSB as B), scan_range[A.FWID,A.FWID]
31                #CSEK2: [1, 1, 0]; scan_type(UNIQUE), INDEX33568936(T_XMGK_FWZTB as C), scan_range[B.FWID,B.FWID]
32            #BLKUP2: [1, 1, 0]; INDEX_XMGK_FCFFWGXB_FWID(FCF)
33              #SSEK2: [1, 1, 0]; scan_type(ASC), INDEX_XMGK_FCFFWGXB_FWID(T_XMGK_FCFFWGXB as FCF), scan_range[A.FWID,A.FWID]
*/

执行计划解析:

  1. 首先将主查询中四张表做完连接(三个内连接、一个外连接),把中间结果集放在临时表DMTEMPVIEW_16784484(堆表:支持无序地并发插入)中并且进行编号table_no(0)。
  2. SPL2操作符下主要是将HEAP TABLE(DMTEMPVIEW_16784484)临时结果集带入标量子查询 T_CWZS_CWZSAJB和T_CWZS_CWAJB连接后进行相关子查询条件aj.fwid= a.fwid,可以理解成子查询平坦化。
  3. 标量子查询的子计划出现NEST LOOP [with var]字眼,说明存在变量改写后嵌套循环传递的连接方式,特别值得注意它是性能杀手
  4. 观察操作节点13 SLCT2 AJ.FWID = var1,由HEAP TABLE临时表结果集传入变量值过滤,又因T_CWZS_CWAJB表的数据量有点大56W行,在NEST LOOP连接方式的控制下,
    被反复地全表扫描再过滤,加重HEAP TABLE结果集较大的情况下,执行效率慢合乎常理。
  5. 取出临时表DMTEMPVIEW_16784484按CAST(regexp_replace(a.ch/a.fwh, ‘([0-9]-[0-9])|[^-0-9.]’) as int)排序,目的是按数值方式排序(而不是字符对应的ASCII码表)。
  6. 排序完成后,将SPL2临时结果集进行AUTOID拼接结果,则全表的最终结果集就可获得SELECT所有查询项的值(包含标量子查询返回的关联列的计算值)。

2.2 ET定位耗时操作符

依据日常经验和执行计划关键点跟踪,大概率认为性能杀手在于标量子查询处,也就是SPL2子计划树。
有时凭借长时间的经验总结,80%问题能够解决,但也会在所谓的经验面前栽跟头。应该客观且科学性的分析问题,此时ET性能定位工具出场。
ET工具使用,建议以会话级的方式设置生效,免得影响生产环境,测试环境另当别论。

-- 执行SQL窗口打开SQL执行消耗监控
/*
普通用户:grant execute on sys.et to xxx;
*/
sf_set_session_para_value('monitor_sql_exec', 1);
call et(执行号);
/*
当时已弄好,忘了截图,此处仅提供方法学习
当时看到执行计划中4号节点PRJT2非常消耗时间,即SPL2右节点存在严重的性能问题,也就是标量子查询。
结合SPL2子计划树中WITH VAR的字眼,更好确定问题点,则应该着重优化标量子查询。
*/

在这里插入图片描述

2.3 注释大法

步骤2的跟踪已经接近现实,为了百分之百坚定问题根源,时而利用一下注释方法也挺便捷的,对SELECT中标量子查询括起注释,再次执行查询语句,返回时间极短。 此处不再具体演示,介绍常用方法足够。


3. 解决方法

3.1 HINT功法

1.禁止变量改写,转为HASH LEFT JOIN2,减少SPL2子计划树中标量子查询两表的全表扫描次数。

2.执行计划大体方向变化不大,仅是在处理子查询平坦化时,采用哈希连接,操作节点编号10与13发生变化(不启用变量改写)。

select /*+ NO_USE_CVT_VAR */ ...

-- 执行计划
/*
1   #NSET2: [184, 1, 3408] 
2     #PIPE2: [184, 1, 3408] 
3       #PIPE2: [183, 1, 3408] 
4         #PRJT2: [2, 1, 3408]; exp_num(75), is_atom(FALSE) 
5           #SORT3: [2, 1, 3408]; key_num(2), is_distinct(FALSE), top_flag(0), is_adaptive(0)
6             #HEAP TABLE SCAN: [1, 1, 3408]; table_no(0), 
7         #SPL2: [181, 1, 3760]; key_num(2), spool_num(0), is_atom(FALSE), has_variable(0) 
8           #PRJT2: [181, 1, 3760]; exp_num(3), is_atom(FALSE) 
9             #HAGR2: [181, 1, 3760]; grp_num(1), sfun_num(5); slave_empty(0) keys(DMTEMPVIEW_16794534.AUTOID) 
10              #HASH LEFT JOIN2: [180, 1, 3760]; key_num(1), partition_keys_num(0), ret_null(0), mix(0) KEY(DMTEMPVIEW_16794534.ORDER_COL2=AJ.FWID)
11                #HEAP TABLE SCAN: [1, 1, 3408]; table_no(0), 
12                #SLCT2: [126, 484137, 352]; AJ.DEL_FLAG = '0'
13                  #HASH2 INNER JOIN: [126, 484137, 352];  KEY_NUM(1); KEY(CW.AJXXID=AJ.AJXXID) KEY_NULL_EQU(0)
14                    #SLCT2: [1, 1306, 200]; (CW.DEL_FLAG = '0' AND CW.JLZT = '1')
15                      #CSCN2: [1, 2516, 200]; INDEX33569078(T_CWZS_CWZSAJB as CW)
16                    #CSCN2: [74, 550864, 152]; INDEX33569077(T_CWZS_CWAJB as AJ)
17      #HEAP TABLE: [1, 1, 3408]; table_no(0) full(FALSE), mpp_full(0) autoid(TRUE)
18        #PRJT2: [1, 1, 3408]; exp_num(72), is_atom(FALSE) 
19          #INDEX JOIN LEFT JOIN2: [1, 1, 3408] join condition(FCF.DEL_FLAG = '0') ret_null(0)
20            #SLCT2: [1, 1, 3408]; (C.DEL_FLAG = '0' AND C.HQLX <> '2' AND A.FWID = C.FWID)
21              #NEST LOOP INDEX JOIN2: [1, 1, 3408] 
22                #SLCT2: [1, 1, 1914]; B.DEL_FLAG = '0'
23                  #NEST LOOP INDEX JOIN2: [1, 1, 1914] 
24                    #MERGE INNER JOIN3: [1, 1, 1410]; KEY_NUM(1); KEY(COL_4 = COL_1) KEY_NULL_EQU(0)
25                      #SLCT2: [1, 21, 1266]; A.DEL_FLAG = '0'
26                        #BLKUP2: [1, 22, 1266]; INDEX_XMGK_FWB_MPID(A)
27                          #SSEK2: [1, 22, 1266]; scan_type(ASC), INDEX_XMGK_FWB_MPID(T_XMGK_FWB as A), scan_range['112','112']
28                      #SLCT2: [1, 1, 144]; MP.DEL_FLAG = '0'
29                        #CSEK2: [1, 1, 144]; scan_type(UNIQUE), INDEX33568939(T_XMGK_MPB as MP), scan_range['112','112']
30                    #CSEK2: [1, 1, 0]; scan_type(UNIQUE), INDEX33568938(T_XMGK_FWFSB as B), scan_range[A.FWID,A.FWID]
31                #CSEK2: [1, 1, 0]; scan_type(UNIQUE), INDEX33568936(T_XMGK_FWZTB as C), scan_range[B.FWID,B.FWID]
32            #BLKUP2: [1, 1, 0]; INDEX_XMGK_FCFFWGXB_FWID(FCF)
33              #SSEK2: [1, 1, 0]; scan_type(ASC), INDEX_XMGK_FCFFWGXB_FWID(T_XMGK_FCFFWGXB as FCF), scan_range[A.FWID,A.FWID]
*/

在这里插入图片描述

3.2 改写功法

标量子查询改为左外连接。

SELECT
        a.fwid                                         ,
        a.ldid                                         ,
        a.mpid                                         ,
        a.MYCH                                         ,
        a.CH                                           ,
        a.fwh                                          ,
        a.th                                           ,
        a.fh                                           ,
        a.dh                                           ,
        a.fwlx                                         ,
        c.fwgn                                         ,
        c.fwgn fwgncode                                ,
        c.jtgn                                         ,
        b.cg                                           ,
        b.fwhx                                         ,
        a.dz                                           ,
        a.mp                                           ,
        a.ZJZMJ as zmj                                 ,
        a.TNMJ                                         ,
        a.GTMJ                                         ,
        b.fbyt                                         ,
        b.FFBYT                                        ,
        b.cf                                           ,
        b.wsj                                          ,
        b.dq                                           ,
        b.xq                                           ,
        b.nq                                           ,
        b.bq                                           ,
        c.HTAH                                         ,
        c.yzzt                                         ,
        c.QQAH                                         ,
        c.QQZT                                         ,
        REPLACE(a.ch, '夹', '') pxch                    ,
        nvl(c.zyzlzt, 0) zyzlzt                        ,
        a.jzjg                                         ,
        c.djzt                                         ,
        c.htzt                                         ,
        a.jlzt                                         ,
        decode(c.sfhq, '0', '0', '1', '1', '0')sfhq    ,
        decode(c.sfzy, '0', '0', '1', '1', '0')sfzy    ,
        decode(c.sfgjpt, '0', '0', '1', '1', '0')sfgjpt,
        decode(c.sfxjf, '0', '0', '1', '1', '0')sfxjf  ,
        c.xzzt                                         ,
        c.yyzt                                         ,
        c.dyzt                                         ,
        c.sfzg sfzg                                    ,
        mp.dz mpdz                                     ,
        c.sffc                                         ,
        a.jjmj                                         ,
        c.fwyt                                         ,
        a.xzqh xzqh_code                               ,
        a.beiz                                         ,
        a.fcgbz                                        ,
        c.sfbj                                         ,
        c.gjptfl                                       ,
        a.YSZJZMJ                                      ,
        a.YSTNMJ                                       ,
        a.YSGTMJ                                       ,
        c.djah fwb_djah                                ,
        c.JZMJDJ                                       ,
        c.TNMJDJ                                       ,
        a.chbdcdyh                                     ,
        a.chah                                         ,
        a.sfxgchmj                                     ,
        c.JCYFWZT                                      ,
        c.hbfgsdzt                                     ,
        nvl(c.islock, 0) islock                        ,
        c.hqlx hqlx                                    ,
        c.DJAH DJAH                                    ,
        a.xzqh xzqh                                    ,
        C.SFJGBA SFJGBA                                ,
        C.SFCWBA SFCWBA                                ,
        
        -- 改写内容块  --
        decode(c.sfcwba, '1', Sblx0, '') Sblx          ,
        -- 改写内容块  --
        
        a.kfsid kfsid,
        c.sfgycq sfgycq
FROM
        T_XMGK_FWFSB b,
        T_XMGK_MPB mp ,
        T_XMGK_FWZTB c,
        T_XMGK_FWB a
left join T_XMGK_FCFFWGXB fcf
on
        fcf.FWID     = a.FWID
    and fcf.del_flag = '0'
    
-- 改写内容块  --
left join  
(
    select
            aj.fwid,
            decode(max(cw.balx), '1', '出售(1:1)', '3', '整体转让', '出售(大于1:1)') Sblx0
    from
            T_CWZS_CWZSAJB cw,
            T_CWZS_CWAJB aj
    where
            cw.ajxxid   = aj.ajxxid
        and cw.del_flag = '0'
        and aj.del_flag = '0'
        and cw.jlzt     = '1'
    group by aj.fwid   
) x
on x.fwid = a.fwid
-- 改写内容块  --

WHERE
        a.FWID      = b.FWID
    and b.FWID      = c.FWID
    and a.mpid      =mp.mpid
    and b.del_flag  = '0'
    and a.del_flag  = '0'
    and c.del_flag  = '0'
    and mp.del_flag = '0'
    and a.mpid      = '112'
    and c.hqlx     <> '2'
Order By
        CAST(regexp_replace(a.ch, '([0-9]-[0-9])|[^-0-9.]') as  int),
        CAST(regexp_replace(a.fwh, '([0-9]-[0-9])|[^-0-9.]') as int);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值