注册
初次接触复杂慢SQL如何优化
专栏/技术分享/ 文章详情 /

初次接触复杂慢SQL如何优化

诗想与论语 2026/10/10 192 2 0
摘要

初次进入职场的新人DBA,都不可避免的要面对一个问题,就是慢SQL的优化,那么面对一系列复杂的SQL语句,我们第一次接触,不知道从何下手,应该如何去分析,一些根据如何去使用,思路如何整理,本文以三个慢SQL为例,介绍首次面对复杂的SQL语句,如何去优化拓展。

1文本工具:

要执行分析,首要是对信息的采集和文本的分析,那么首先一个方便高效的文本分析工具就颇为重要,这里推荐Notepad++文本工具下载链接如下:
https://github.com/notepad-plus-plus/notepad-plus-plus
后续在使用中会介绍工具的使用

2SQL分析工具:

针对慢SQL的分析,我们最基础的信息需要拿到,并从拿到的信息进行分析,这里需要我们学习使用两个达梦的工具,TRACE和ET

2.1ET

ET是达梦数据自带的SQL性能分析工具,能够统计SQL语句执行过程中每个操作符的实际开销,为SQL优化提供依据。
ET与执行计划的区别是:
执行计划告诉你SQL为什么慢,ET告诉你实际哪里做得慢,也就是哪一个步骤花了多少时间
ET功能默认是关闭的,需要通过INI参数开启,此为动态参数,无需重启:
SP_SET_PARA_VALUE(1,‘ENABLE_MONITOR’,1);
SP_SET_PARA_VALUE(1,‘MONITOR_SQL_EXEC’,1);
检查ET功能状态:
SP_SET_PARA_VALUE(1,‘ENABLE_MONITOR’,0);
SP_SET_PARA_VALUE(1,‘MONITOR_SQL_EXEC’,0);
image.png
如果都输出1,即代表功能已经开启。

2.2TRACE

TRACE是达梦数据库提供的SQL执行过程跟踪工具,它能让你看到执行过程中的详细行为,比如实际访问了哪些索引,读取了多少行数据,走了什么路径等等。
常用在需要确认SQL执行过程中实际访问了哪些表和索引,以及需要获取SQL执行的详细统计信息,如实际读取的行数,物理读次数,逻辑读次数等等情况。
在disql命令行中查看SQL真实执行计划:
先确保相关监控参数已开启:
SP_SET_PARA_VALUE(1,‘ENABLE_MONITOR’,1);
SP_SET_PARA_VALUE(1,‘MONITOR_SQL_EXEC’,1);
SP_SET_PARA_VALUE(1,‘ENABLE_MONITOR_DMSQL’,1);
基本用法:
在disql中执行SET AUTOTRACE TRACE,然后运行SQL语句

SET AUTOTRACE TRACE;
SELECT * FROM SYSOBJECTS WHERE NAME = ‘TEST’;
image.png
执行后,除了查询结果,还会打印出真实的执行信息和统计信息。
以上两个工具是我们做最基础的SQL分析最主要的两个工具,我们的分析思路也是围绕这两个工具所提供的信息来进行的。下面我们开始进行案例的分析

3案例一:

在分析之前,先将SQL语句、ET和trace分别放入文本分析工具中,用作分析,示例如下:

image.png
分析思路:
首先查看ET中,耗时最长的操作符,可以看到最长的占据36%的时间,双击数字1(耗时排名)定位到第41行(trace行数)的回表操作符
image.png
之后再到TRACE里面去到41行查看对应的部分,即绿色部分
由图中41行可以看到,从T_KE_JOURNALS表中取数据,走的是T_KE_JOURNALS_ORGID_IDX3这个索引,而这个索引确扫描了120万行数据,产生了大量的回表,说明它的过滤效果极差,没有起到很好的作用。
双击T_KE_JOURNALS表名锁定它(双击变绿),来到SQL文本这里,观察到这里的两个字段,一个是ORG_ID,另一个是CANCELFLAG,这两个字段作为过滤条件。经查询索引结构,T_KE_JOURNALS_ORGID_IDX3是ORG_ID上的索引,而CANCELFLAG上面也有索引,但是这两个字段都无法进行很好的过滤,因此此处无法进行优化。
image.png
继续进行排查,来到耗时第二高的第21行,双击之后变绿,然后来到trace第21行查看相关的操作符
image.png
来到trace的第21行,可以看到这里的操作是一个投影操作符PRJT2,投影是关系代数中的基本运算,它的作用是在查询结果中选择并计算最终需要输出的表达式项(比如字段、函数、CASE WHEN 表达式、子查询等)
exp_num 是 PRJT2 操作符的专属参数,表示该投影节点需要计算并输出的表达式数量,exp_num(4) 意味着这个 PRJT2 节点负责计算 4 个表达式,而这四个表达式中含有两个标量子查询,如下图中的图2
image.png
图2:image.png
这两个子查询的过滤条件完全一样,仅有DEBITCREDITFLAG的结果一个等于1,一个等于2,而这两个标量子查询查看ET下,第3耗时的正是这两个子查询image.png
查看它对应的执行计划:
image.png
发现有大量的回表,这正是SQL慢的原因。
此时的优化思路便是,将这两个子查询合并为一个子查询,那么即可提升30%的效率,改写后的SQL语句如下:
image.png
新SQL的过滤条件就是原来两个标量子查询里公共的那部分,只写一次,DEBITCREDITFLAG in (‘1’,‘2’) 是为了处理收入/支出两种方向进行分流,采用left join生成派生表的形式可以返回多行,这样即可完成优化。

4案例二:
同样将SQL语句,ET和trace分别放入文本分析工具,之后开始分析
分析思路:
分析的第一步,同样是定位耗时最长的操作符,来到ET下查看:
image.png
是第25行的回表,那么对应的来到TRACE中查看:
image.png
查看到第25行中,扫描了120万行数据,产生了大量回表,而它走的是T_KE_JOURNALS_ORGID_IDX3这个索引,那么我们可以得知这个索引的过滤下极差,查看T_KE_JOURNALS表结构,他还存在其他的索引,通过inviable将原索引不可见 调到指定索引上T_KE_JOURNALS_ORGID_IDX上,发现SQL效率大幅提升,说明该索引正确有效,过滤性好,那么优化目标便是将索引走到T_KE_JOURNALS_ORGID_IDX目标索引上。
初步优化方案是更新统计信息,以防止是因为统计信息未及时更新导致的索引走错,但是在重新收集后未生效。
第二步是使用hint绑定,强制使用目标索引,但是使用后依旧未生效,此时排查一下image.png
对比一下在优化器中,两个索引的统计信息,优化器认为原索引比目标索引更加性能优异,在索引过多的情况下,hint有很大的概率会失效。
第三步,采用改写SQL的方式,指定目标索引,语法则是
from 表名 index索引名 表别名
例如:from T_KE_JOURNALS index T_KE_JOURNALS_ORGID_IDX t
因此,优化后的SQL如下:

image.png
注意:应急状态下多采用hint绑定的方式,SQL应用改写周期长,不能马上改写马上重新部署。

5案例三:

同样需要将SQL文本、ET与trace放到文本分析工具中
分析思路:
分析方法一致,来到ET中最耗时的一行,并定位TRACE中的位置,可以看到这是一个NLS2操作符,即嵌套循环。
image.png
嵌套循环:外层循环(驱动表)读取一行数据,然后传入内层循环(被驱动表)去查找匹配的行。如果内层表有索引且过滤性好,这种算法效率极高;如果没有索引或无法使用索引,就会退化为笛卡尔积,性能极差。
在Trace中对应的操作符如下:
image.png
这里有一个过滤条件: exp11 > 0,对应SQL文本中的instr 函数运算,如下图),数据库无法利用 T_BU_BUDGETORGANIZATION 表上的 ORG_ID 索引或者 TENANTID 索引直接定位数据。因为数据库中函数无法使用索引,因此在第29行出现了CSCN2,即全表扫描,产生了大量的数据扫描,那么即可锁定SQL慢的原因,函数的写法导致大表只能嵌套循环且全表扫描,我们可以从这个方向进行优化。

image.png
嵌套循环的查找方式,类似使用字符串去模糊对比,例如A/B,去找到下面A/B/C、A/B/D、A/B/E/F之类的所有子字符串,结合SQL中的业务需求,需要查找到父机构下的所有子机构,那么我们可以采用层次查询,顺着父ID去查询子ID,这样也可以快速查询到所有的子对象,优化后的SQL如下:
image.png

6总结:

本文介绍了三种具有代表性的慢SQL优化方法,包括合并子查询,修改索引已经修改查询结构,几种方法并不代表全部的方案,更多的是分享一种思路,当新手首次遇到慢SQL分析的任务时,从哪里入手,以及文本工具如何去使用可以快速定位相应的信息所在,以便于学习与进步。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服