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

  • 1. 场景描述
  • 2. 分析过程
    • 2.1 查看原始SQL执行计划
    • 2.2 ET定位耗时操作符
    • 2.3 注释大法
  • 3. 解决方法
    • 3.1 HINT功法
    • 3.2 改写功法

DM技术交流QQ群:940124259

1. 场景描述

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


2. 分析过程

2.1 查看原始SQL执行计划

explain
SELECTa.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                                ,(selectdecode(c.sfcwba, '1', decode(max(cw.balx), '1', '出售(1:1)', '3', '整体转让', '出售(大于1:1)'), '')fromT_CWZS_CWZSAJB cw,T_CWZS_CWAJB ajwherecw.ajxxid   =aj.ajxxidand aj.fwid     = a.fwidand cw.del_flag = '0'and aj.del_flag ='0'and cw.jlzt     = '1')Sblx         ,a.kfsid kfsid,c.sfgycq sfgycq
FROMT_XMGK_FWFSB b,T_XMGK_MPB mp ,T_XMGK_FWZTB c,T_XMGK_FWB a
left join T_XMGK_FCFFWGXB fcf
onfcf.FWID     = a.FWIDand fcf.del_flag = '0'
WHEREa.FWID      = b.FWIDand b.FWID      = c.FWIDand a.mpid      =mp.mpidand 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 ByCAST(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 改写功法

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

SELECTa.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
FROMT_XMGK_FWFSB b,T_XMGK_MPB mp ,T_XMGK_FWZTB c,T_XMGK_FWB a
left join T_XMGK_FCFFWGXB fcf
onfcf.FWID     = a.FWIDand fcf.del_flag = '0'-- 改写内容块  --
left join
(selectaj.fwid,decode(max(cw.balx), '1', '出售(1:1)', '3', '整体转让', '出售(大于1:1)') Sblx0fromT_CWZS_CWZSAJB cw,T_CWZS_CWAJB ajwherecw.ajxxid   = aj.ajxxidand cw.del_flag = '0'and aj.del_flag = '0'and cw.jlzt     = '1'group by aj.fwid
) x
on x.fwid = a.fwid
-- 改写内容块  --WHEREa.FWID      = b.FWIDand b.FWID      = c.FWIDand a.mpid      =mp.mpidand 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 ByCAST(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);

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

  1. 性能为王:SQL标量子查询的优化案例分析

    本篇整理内容是黄廷忠在"云和恩墨大讲堂"微信分享中的讲解案例,SQL优化及SQL审核,是从源头解决性能问题的根本手段,无论是开发人员还是DBA,都应当持续深入的学习SQL开发技能, ...

  2. 标量子查询产生的SQL性能瓶颈,该怎么合理优化?

    来自:DBAplus社群 作者介绍 郝昊喆,新炬网络数据库专家.擅长数据库方面的开发.整体架构及复杂SQL的调优,参与了多个行业核心系统的优化工作,目前专注于对开源技术.自动化运维和性能调优技术的研究 ...

  3. 子查询及其分类(标量子查询+列子查询+行子查询+表子查询)

    子查询 什么是子查询 子查询概念 子查询:sub query 子查询是一种常用计算机语言SELECT-SQL语言中嵌套查询下层的程序模块.当一个查询是另一个查询的条件时,称之为子查询. 子查询:指在一 ...

  4. mysql三重连接查询_sql子查询,多重查询,join,左连接,右连接,内连接

    范围内重复数量查询 根据上表查询 每个手机号都各有多少个重复的设备id SELECT t.phone_num,COUNT(*) FROM (select phone_num, device_id,co ...

  5. mysql 事b务 查询_MySQL进阶学习笔记二(包括连接查询、子查询、联合查询、事务、存储过程)...

    1.高级查询 (1)了解笛卡尔积:笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尔积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序 ...

  6. server多笔记录拼接字符串 sql_第四章、SQL Server数据库查询大全(单表查询、多表连接查询、嵌套查询、关联子查询、拼sql字符串的查询、交叉查询)...

    4.1.查询的类型 declare @value as int set @value = 50 select  'age:'as age,2008 years,@valueas va --这种查询时跟 ...

  7. PostgreSQL中的查询:1.查询执行阶段

    PostgreSQL中的查询:1.查询执行阶段 开始关于PG内部执行机制的文章系列.这一篇侧重于查询计划和执行机制. 本系列包括: 1.查询执行阶段(本文) 2.统计数据 3.顺序扫描 4.索引扫描 ...

  8. mysql join on 索引_连接查询,表关联查询join on,索引,触发器,视图

    一.连接查询 1.统计每一个部门的人数  "部门名,部门的人数" select department,count(eid) from employee group by depar ...

  9. db2嵌套查询效率_嵌套查询与连接查询的性能

    嵌套查询与连接查询的性能:连接查询一般较快:子查询很难被优化.(当然和DB优化有关,也可能子查询比连接查询快)其实不能一概而论的~~ 不过,问了下DBA同学,他建议是能用join的,尽量不要用嵌套查询 ...

最新文章

  1. 置顶带滚动效果_高端大气的滚动条图表,你学会了还怕老板们不喜欢,不升职吗?...
  2. ASP.NET中的数据绑定:哪个更快? (转)
  3. php linux权限,Linux权限详细介绍
  4. Ubuntu根目录下各文件的功能介绍
  5. 虚拟机与主机串口通信(主机与主机)
  6. .net 链oracle,.net链数据库oracle
  7. Jquery 获取 radio选中值(转)
  8. AcWing327.玉米田(状压DP)题解
  9. 在IDEA中创建Maven项目和添加tomcat
  10. 省市区的行政区域数据2021(国家统计局)
  11. Swagger注解 详解
  12. 【Flask+SocketIO】如何用Flask做一个快捷迷你的局域网聊天室
  13. 显示upnp服务器 sonos,四步解决UPNP功能被阻塞的问题
  14. python文本文件操作诗句给上一句输出下一句_使用RNN生成文本实战:莎士比亚风格诗句...
  15. 计算机毕业设计 java餐厅点餐系统 餐厅管理系统 餐厅点餐系统java 餐厅预定系统 餐厅预订系统 点餐座位预定系统 餐厅后台管理系统 点餐系统 外卖点餐系统 springboot餐厅预约系统
  16. 浅谈sstream头文件
  17. 右中秋夜大观园即景联句三十五韵
  18. POL8901 LVDS转MIPI DSI 支持旋转图像处理芯片
  19. Linux 学习网站汇总
  20. eclipse java jde,Eclipse平台入门之一:什么是Eclipse,我们将开始介绍Java 开发环境(JDE)。...

热门文章

  1. 中国人最需要的“基础文明”有三项
  2. 马走日,象走田;车走直路炮翻山
  3. 大数据治理平台架构技术方案(ppt)
  4. 锂电池等效电路模型二阶RC模型二阶戴维南模型
  5. 如何将多台物理机整合成一台
  6. 骂谷歌,怼百度,批腾讯,吴军为何DISS互联网公司没得怕的?
  7. 张小龙演讲全文:如何把产品做简单
  8. 第三代总线技术迈向2.5G SDH(转)
  9. 通过Http调用第三方接口,收不到返回信息
  10. 临汾第一站软件工作室网站建成运行……