注册
DM8 SQL优化实战
培训园地/ 文章详情 /

DM8 SQL优化实战

Z 2026/10/08 362 0 0

第一章 总体介绍

1.1 什么是慢SQL

慢SQL是指执行时间明显超过正常预期、或消耗资源异常的SQL语句。分为两类:一种是单次很慢,一条SQL跑几秒甚至几分钟(如全表扫描千万行),仅仅这一条语句就拖垮业务;另一种是单条不慢但是频率很高的语句,它被大量会话高频反复执行,累积把CPU/IO占满,导致整体变慢。

1.2 什么是SQL优化

SQL优化是指在不改变业务逻辑的前提下,通过调整SQL写法、合理建立索引、维护统计信息、干预执行计划等手段,让查询优化器为SQL语句选择代价更低的执行计划,从而降低响应时间、减少资源消耗的过程。达梦数据库的查询优化器会基于统计信息对语句的多种执行方式进行代价估算,并选择代价最小的计划。

1.3 优化目标与衡量标准

我们主要从三个方面去判断一个SQL语句执行的快慢,其一是SQL语句的响应时间,就是从发出SQL语句到的到返回结果的时间,是用户最直接的感应指标也是优化的首要指标;其次是吞吐量,指的是单位时间内完成的查询或事务数量;最后是资源消耗,指的是CPU、内存、磁盘IO等的开销,资源消耗过高的SQL会拖慢整个数据库的速度。我们对于SQL优化应该优先处理执行次数多且单次耗时长的SQL,这类SQL对于整体性能的影响最大,生产环境中常见做法就是先筛选所有的慢SQL,然后跟据影响性能的程度,从影响大的开始优化。

1.4 优化总体流程

SQL优化总体分为以下5个步骤,第一步,定位慢SQL,通过动态视图或者SQL日志找出高负载的SQL语句;第二步,查看执行计划,确认SQL语句的执行计划;第三步,通过工具找出执行计划中耗时占比最高的操作符;第四步,通过改写SQL,调整索引,更新统计信息等方法进行优化;第五步,通过对比优化前后的SQL执行时间,来确定优化是否到达理想的效果。

第二章 定位慢 SQL

2.1 打开监控开关

达梦的性能监控大部分是默认开启的,但是如果需要使用ET、AUTOTRACE等功能时需要注意三个参数,第一个是ENABLE_MONITOR,这个参数是是否启用系统监控,设置为1表示开启系统监控,能够收集最近执行的SQL记录以及动态视图;第二个参数是MONITOR_TIME,设置为1表示开启时间监控,记录SQL的实际执行时间;第三个参数是MONITOR_SQL_EXEC,设置为1表示开启SQL执行监控,收集SQL执行详情。

CALL SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);
CALL SP_SET_PARA_VALUE(1,'MONITOR_TIME',1);
CALL SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',1);

如果只需要在当前会话临时开启,可以使用会话级设置函数,

SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC',1);

2.2 动态视图定位高负载 SQL

开启监控后,可以执行以下SQL语句查询动态视图筛选出执行时间最长的语句:

SELECT SESS_ID, SQL_TEXT, EXEC_TIME, N_RUNS, FINISH_TIME
FROM V$LONG_EXEC_SQLS ORDER BY EXEC_TIME DESC;

其中V$LONG_EXEC_SQLS可以查询超过预定时间的SQL语句,默认时间阈值为1000毫秒。V$SYSTEM_LONG_EXEC_SQLS可以查询服务器启动以来执行时间最长的20条SQL语句。从视图筛选到目标慢SQL后,先观察其执行次数和执行时间,判断是单次执行时间长还是需要执行次数多,反复执行导致时间变长,再进入下一步分析。

2.3 跟踪日志与慢 SQL 过滤

达梦的跟踪日志文件以dmsql_实例名_日期_时间命名,日志里面记录语句的执行时间等信息。当慢SQL没有触发监控阈值且需要在海量历史语句中筛选时,可以在日志文件中按耗时正则过滤,把执行时间超过阈值的语句摘出来进行分析。例如查找执行时间超过10秒的语句,再结合应用侧的业务日志确认语句来源。

2.4 ET工具定位执行瓶颈

在筛选出慢SQL后,可以用ET工具统计该语句执行计划中每一个操作符的执行时间,能够快速定位是因为哪一个步骤花的时间长,具体可分为以下三个步骤,第一步为确认三个监控参数已开启(见 2.1);第二步,在会话中执行目标SQL,并记录返回的“执行号”(例如 916)。第三步则是调用ET过程查看该执行号的统计结果:CALL ET(916);
ET输出中各列的含义如下,OP为操作符名称;TIME(US),操作符执行耗时,单位是微秒;PERCENT是该操作符耗时占整个计划的比例;RANK为耗时排名;N_ENTER为操作符进入的次数。

第三章 读懂执行计划

3.1 查看执行计划的方法

达梦DISQL查看执行计划的方法有很多,按是否真正执行其SQL语句可分成两类:一类只生成计划、不执行语句,包括EXPLAIN和EXPLAIN FOR。EXPLAIN的优点就是开销小、速度快,但计划是估算的,可能与实际执行不一致;EXPLAIN FOR与EXPLAIN类似,但计划以结果集返回并保存在会话级临时表PLAN_TABLE中,信息更丰富,还包含创建索引建议(ADVICE_INFO字段)、分区起止信息等,方便做计划对比。另一类则真正执行语句,包括SET AUTOTRACE TRACE、ET、PLNDUMP。SET AUTOTRACE TRACE会真正执行语句并打印实际执行计划,因为是实际执行的计划(可能来自计划缓存),比EXPLAIN的估算结果更可信,是日常分析的首选;ET统计执行计划中每个操作符的实际执行时间,用于定位瓶颈;PLNDUMP(CACHEPLAN)从计划缓存中导出指定SQL的执行计划,常用于抓取存储过程内部SQL的计划。其中EXPLAIN FOR和ET用得最多。

3.2 常用操作符解读

达梦的执行计划由一棵操作符树构成,读懂操作符是分析计划的基础,常见操作符含义如下:NSET2是结果集节点,通常是计划的最顶层;PRJT2是投影,负责对列进行裁剪、计算;CSCN2是全表扫描(普通表);CSEK2是聚集索引定位扫描,按聚集索引键定位数据;SSEK2是二级索引定位扫描,按二级索引定位数据;SLCT2是过滤,对扫描结果按条件筛选;NEST LOOP是嵌套循环连接;HASH2 INNER JOIN是哈希连接;SORT是排序;HAGR2是分组聚合;ACTRL是备用计划控制,优化器生成了备用计划并择优选择。看执行计划时要重点关注三点:表访问方式(是CSCN2全表扫描,还是SSEK2/CSEK2走索引)、连接方式(嵌套循环还是哈希连接)、连接顺序(哪张表作为驱动表),大多数性能问题的根源都出在这三处。

3.3 统计信息:执行计划的地基

优化器估算代价依赖统计信息,统计信息过期或缺失时,优化器对行数、基数的估算会有严重失真的后果,从而可能选错计划,比如明明能走索引却走了全表扫描,或者连接顺序颠倒,所以在数据量发生大幅变化如大批量插入、删除、更新后,应当及时重新收集统计信息。常用的收集方式有四种,收集指定表的统计信息用CALL SP_TAB_STAT_INIT('SYSDBA','TEST_BIG');;收集指定表上所有索引的统计信息用CALL SP_TAB_INDEX_STAT_INIT('SYSDBA','TEST_BIG');;使用DBMS_STATS包收集表及列统计信息用 DBMS_STATS.GATHER_TABLE_STATS('SYSDBA','TEST_BIG',NULL,100,TRUE,'FOR ALL COLUMNS SIZE AUTO',2);;收集指定用户下所有表的统计信息用 DBMS_STATS.GATHER_SCHEMA_STATS('SYSDBA',100,TRUE,'FOR ALL COLUMNS SIZE AUTO');。一个典型的案例例如某表TEST_BIG中STATUS=1的数据已经被删除,但由于统计信息未更新,优化器仍以为STATUS=1的数据量很大,执行计划走了 CSCN2 + SLCT2全表扫描;重新执行SP_TAB_STAT_INIT收集统计信息后,同样的SQL计划自动切换为索引扫描,性能问题随之解决。所以遇到SQL突然变慢、执行计划明显不合理的情况,可以先检查统计信息,再决定是不是要改写SQL。

3.4 优化器相关参数

达梦优化器相关的会话级参数主要有两个。第一个是OPTIMIZER_MODE能选择优化器模式,0为老优化器模式采用后序遍历算法,1为新优化器模式采用先序遍历算法,以及扩展了NEST LOOP JOIN等功能,该参数默认值为1,一般建议保持新优化器模式;第二个是FIRST_ROWS是优先返回行数,取值范围为1~1000000,达梦优化器以最快响应时间为优化目标,设置FIRST_ROWS=10表示查询出10条结果就立即返回给用户,适合分页、在线查询类场景,批量报表类场景通常不需要调整。但是需要注意的是,这两个参数都属于会话级动态参数,修改后只影响后续会话的计划选择,不会影响已生成缓存的计划,改参数前建议先在测试环境验证。

第四章 索引优化

4.1 索引类型与适用场景

达梦常用的索引类型主要有五种。聚集索引是每张表只能有一个的索引,默认聚集索引键是ROWID,数据按聚集索引键排序,普通表的数据就存放在聚集索引叶子节点上,它适用于表的默认存储形式,也是主键等值、范围查询的主路径;二级索引是普通辅助索引,通过索引找到ROWID再回表访问数据,适用于高频查询列和复合查询条件;位图索引按位图方式存储,压缩比高,但不支持大字段、计算表达式列、UNIQUE列和PRIMARY KEY,适用于低基数列和OLAP分析场景;函数索引是对表达式建立的索引,必须使用确定性函数,且不能是CLUSTER或PRIMARY KEY类型,适用于查询条件带函数、无法改写为范围条件的场景;覆盖索引是包含查询所需全部列的索引,DM的聚集索引本身就是一种覆盖索引,可以看作瘦表,能够避免回表、减少IO,但会影响插入性能。需要注意的是,位图索引不支持大字段、计算表达式列、UNIQUE列和PRIMARY KEY;覆盖索引虽然能避免回表,但会显著影响插入性能,应该考虑性能代价之后再确定需不需要创建。

4.2 索引设计原则

建立索引时主要遵循五条原则。第一,高选择性优先,过滤后剩余行占比越低的列越值得建索引,全表百万行中区分度极低的列不适合建单列索引;第二,复合索引要注意列顺序,把等值条件的列放在前面、范围条件放在后面,尽量让一条SQL只走一个复合索引;第三,要控制索引数量,每条索引都会带来写放大,DML频繁的表索引越多、插入更新越慢,索引不是越多越好;第四,小表不建索引,只有几万行的表全表扫描代价很低,建索引往往得不偿失;第五,要关注回表次数,二级索引命中大量行时回表代价很高,可以通过覆盖列或聚集索引来优化。

4.3 用HINT干预执行计划

当统计信息正确、SQL也合理,但优化器仍然选择错误计划时,可以使用HINT强制指定访问方式:达梦支持表索引选择HINT,语法为"表名+ INDEX +索引名",或使用注释提示,例如SELECT /*+ INDEX(EMP IDX_EMP_DEPTNO) */ * FROM EMP WHERE DEPTNO = 10;。但使用HINT需要注意,它是最后选择,正常的SQL优化还是优先通过更新统计信息、改写SQL来解决问题;而且数据分布变化后,强制指定的索引可能反过来变差,HINT需要随着数据变化重新评估;还应通过EXPLAIN FOR确认HINT生效,并在计划中看到预期的索引访问方式。

第五章 常见坑与易错点

5.1 一些常踩的认知类坑

1.聚集索引默认键是ROWID,数据按聚集索引键排序,它不是给所有查询加速的万能索引。
2.位图索引适合OLAP,不适合高频DML的OLTP场景。
3.覆盖索引能避免回表,但会影响插入性能,应该先判断性能再决定是否创建。
4.HINT强制指定索引只对当前数据分布有效,数据变化后可能适得其反。
5.查询列表最多2048个字段;FROM子句最多引用100张表,超限会直接报错。
6.复合索引列数、单表索引数量没有硬性上限,但索引越多写入越慢。
7.EXPLAIN是估算计划,可能与实际执行不一致;结论要以SET AUTOTRACE TRACE或ET的实际执行信息为准。

5.2 实战排错建议

1.先看执行计划再优化,没有计划支撑的优化都是猜测,改完很可能无效。
2.一次只改一处,改完进行对比,避免多因素叠加导致无法定位是哪一步起效。
3.学会运用EXPLAIN FOR的ADVICE_INFO优化建议字段,让优化器提示建索引方向。
4.使用ET看耗时占比,优先优化占比最高的操作符。
5.不要在一个方向上死磕,改写、索引、统计信息、参数、HINT多通道尝试,先跑通再细化。
6.优化后必须验证,对比优化前后的执行计划、执行时间等指标,确认没有引入新的问题。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服