达梦数据库执行计划与性能分析入门:EXPLAIN、AUTOTRACE 与 ET

在使用达梦数据库时,经常会遇到一种情况:SQL 可以正常执行,但速度很慢。此时,仅看 SQL 语句本身往往无法找到原因,因为 SQL 只说明"需要查询什么数据",没有说明数据库内部采用什么方式获取这些数据。

例如:

sql 复制代码
SELECT *
FROM EMPLOYEE
WHERE EMP_ID = 1001;

如果 EMP_ID 上存在索引,数据库可能直接定位目标数据;如果没有合适的索引,则可能需要扫描整张表。当数据量较小时,两种方式差别不明显,但当表中存在几十万甚至上百万行数据时,执行方式会直接影响 SQL 性能。

因此,分析慢 SQL 的第一步,是查看数据库为 SQL 生成的执行计划。

一、什么是执行计划

一条 SQL 提交到数据库后,大致会经历以下过程:

text 复制代码
SQL解析
→ 查询优化
→ 生成执行计划
→ 按计划执行
→ 返回结果

其中,查询优化器负责选择 SQL 的执行方式,例如:

  • 使用全表扫描还是索引扫描;
  • 多张表按照什么顺序连接;
  • 使用嵌套循环还是哈希连接;
  • 是否需要排序、聚合或回表;
  • 过滤条件在哪个阶段执行。

执行计划就是优化器最终选择的执行路线。

可以简单理解为:

text 复制代码
SQL:告诉数据库要什么数据
执行计划:告诉数据库怎样得到这些数据

二、怎样阅读执行计划

达梦执行计划通常以树形结构显示,例如:

text 复制代码
NSET2
  PRJT2
    SLCT2
      CSCN2

虽然计划从上到下显示,但数据通常由底层节点产生,再逐层向上传递。因此阅读时应从缩进最深的节点开始。

上面的计划可以理解为:

text 复制代码
CSCN2:扫描表中的数据
SLCT2:按照条件过滤
PRJT2:计算并返回需要的列
NSET2:形成最终结果集

阅读计划时,可以按照以下顺序分析。

1. 看访问了哪些表

先找到计划最底层的表扫描或索引扫描节点,确认 SQL 访问了哪些表。

常见操作符包括:

  • CSCN2:扫描表中的聚集索引数据,常表现为整表扫描;
  • CSEK2:按条件扫描聚集索引;
  • SSEK2:扫描二级索引;
  • BLKUP2:根据二级索引结果回表读取其他列。

如果计划中出现:

text 复制代码
BLKUP2
  SSEK2

说明数据库先通过二级索引找到目标记录,再回到原表读取索引中没有保存的列。

2. 看是否使用索引

看到 SSEK2CSEK2 或具体索引名称,通常说明计划使用了索引。

看到 CSCN2 时,需要判断是否扫描了大量不需要的数据。

但不能简单认为全表扫描一定不好、索引扫描一定更快。

如果 SQL 本身需要读取大部分数据,或者索引条件区分度很低,使用索引后进行大量回表,可能比直接扫描整张表更慢。

因此,判断计划是否合理,需要结合:

  • 表的数据量;
  • 查询返回的数据比例;
  • 索引区分度;
  • 是否需要大量回表;
  • 实际执行时间和读取量。

3. 看过滤条件

执行计划中可能出现:

text 复制代码
access(...)
filter(...)

可以简单理解为:

  • access:用于数据定位或表连接;
  • filter:数据读取后再进行过滤。

如果 SQL 先读取大量数据,之后才进行过滤,通常会产生更多资源消耗。

4. 看表连接方式

多表查询中常见的连接方式包括嵌套循环和哈希连接。

嵌套循环可以理解为:

text 复制代码
从左侧取一行数据
→ 到右侧查找匹配记录
→ 再取下一行
→ 再次到右侧查找

它适合左侧结果较少、右侧连接列有索引的情况。如果左侧返回几十万行,右侧节点也可能被执行几十万次。

哈希连接通常先读取一侧数据建立哈希结构,再扫描另一侧进行匹配,更适合较大结果集之间的等值连接。

连接方式本身没有绝对好坏,需要结合数据量和实际耗时判断。

三、怎样理解计划中的数字

达梦执行计划中经常出现类似内容:

text 复制代码
CSCN2: [10, 1000, 48]

三个数字通常表示:

text 复制代码
[估算代价, 预计行数, 每行数据长度]

1. 估算代价

代价是优化器用于比较不同执行方案的相对指标。

它不是实际执行时间,不能把代价 10 理解为 SQL 执行需要 10 毫秒。

2. 预计行数

预计行数表示优化器估计该节点会处理或返回多少条记录。

如果优化器预计返回 10 行,实际却返回 10 万行,后续连接方式和扫描方式就可能不再合适。

估算不准确可能与以下原因有关:

  • 统计信息过期;
  • 数据分布不均;
  • 多列之间存在关联;
  • 条件中使用函数或隐式类型转换。

3. 每行数据长度

该值表示节点每处理一行数据的大致长度。

返回列越多,每行数据越宽,排序、连接和网络传输的成本通常也越高。因此,在不需要全部字段时,应避免长期使用 SELECT *

四、EXPLAIN:查看优化器生成的预估计划

EXPLAIN 是分析 SQL 执行计划时最基础的工具。它的作用不是执行查询,而是让优化器根据当前的表结构、索引、统计信息和数据库参数,为 SQL 生成一份预估执行计划。

基本形式如下:

sql 复制代码
EXPLAIN
SELECT *
FROM EMPLOYEE
WHERE DEPT_ID = 10;

执行后,数据库不会真正读取并返回查询结果,只会显示优化器准备采用的执行路线。因此,EXPLAIN 适合用于性能分析的第一步。

1. EXPLAIN 实际上在看什么

一条 SQL 通常存在多种可选执行方式。

例如:

sql 复制代码
SELECT *
FROM EMPLOYEE
WHERE DEPT_ID = 10;

优化器可能考虑:

  • 扫描整张 EMPLOYEE 表;
  • 使用 DEPT_ID 上的二级索引;
  • 使用某个包含 DEPT_ID 的联合索引;
  • 先扫描索引,再回表获取其他字段;
  • 在多表查询中改变表的连接顺序;
  • 在嵌套循环、哈希连接等方式之间进行选择。

EXPLAIN 展示的是优化器比较不同候选方案后,最终选择的那一份计划。

因此,EXPLAIN 主要回答的是:

根据优化器目前掌握的信息,这条 SQL 准备怎样执行?

这里的"目前掌握的信息"非常重要。优化器并不知道业务上的真实含义,它主要根据统计信息估算条件会返回多少数据,再决定扫描方式和连接方式。如果统计信息不准确,优化器对数据量的估计就可能出现偏差,最终计划也可能不合理。

2. 查看 EXPLAIN 时应重点关注什么

初学阶段不需要立即分析所有字段,可以先关注以下内容。

数据访问路径

先看最底层节点使用了哪种方式获取数据,例如:

text 复制代码
CSCN2
SSEK2
CSEK2
BLKUP2

重点判断:

  • 是整表数据扫描还是索引扫描;
  • 使用了哪个索引;
  • 是否发生回表;
  • 扫描范围是否与查询条件相符。

例如出现:

text 复制代码
BLKUP2
  SSEK2

说明数据库先通过二级索引找到符合条件的索引记录,再根据索引结果回到原表读取其他列。

这并不一定有问题,但如果索引返回几十万条记录,就可能产生大量回表,实际性能未必比全表扫描更好。

表连接顺序

对于多表查询,要看哪张表先产生数据,哪张表后参与连接。

在嵌套循环中,左侧节点通常是驱动侧。左侧返回多少行,可能直接决定右侧节点被调用多少次。

如果优化器原本估计左侧只返回 10 行,实际却返回 10 万行,那么右侧索引扫描也可能被重复执行 10 万次。

连接方式

计划中需要关注:

  • 嵌套循环连接;
  • 哈希连接;
  • 归并连接。

不同连接方式适合不同的数据规模。EXPLAIN 可以帮助判断优化器是否因为预计结果集较小而选择嵌套循环,或者因为预计数据量较大而选择哈希连接。

预计行数

执行计划三元组中的第二个值通常表示预计处理或输出的行数。

例如:

text 复制代码
CSCN2: [10, 1000, 48]

其中 1000 表示优化器预计该节点会处理大约 1000 行。

预计行数会影响:

  • 是否使用索引;
  • 选择哪张表作为驱动表;
  • 使用哪种连接方式;
  • 是否进行排序;
  • 为哈希、排序等操作分配多少资源。

因此,看计划时不能只看有没有索引,还要看优化器对数据量的估计是否符合实际业务情况。

过滤条件的位置

此外,还需要检查 WHERE 条件是在底层扫描阶段生效,还是读取大量数据之后才进行过滤。

如果条件能够限制索引扫描范围,数据库可能只访问少量数据;如果条件只能作为上层 filter 使用,则可能先读取大量记录,再排除其中大部分。

3. 为什么 EXPLAIN 只是"预估计划"

EXPLAIN 不真正执行 SQL,因此计划中的代价和行数都是估算值。

它无法直接告诉我们:

  • SQL 实际执行了多长时间;
  • 每个节点实际返回多少行;
  • 实际发生多少逻辑读和物理读;
  • 是否发生磁盘排序;
  • 某个节点实际进入了多少次;
  • 时间主要消耗在哪一个操作符。

所以,即使 EXPLAIN 看起来正常,也不能证明 SQL 的实际执行一定正常。

例如:

text 复制代码
优化器预计返回10行
实际执行返回20万行

如果计划选择依赖"只返回 10 行"这一前提,实际执行就可能与预估结果产生巨大差异。

这也是为什么性能分析不能停留在 EXPLAIN,而需要继续使用 AUTOTRACE 和 ET 查看真实执行情况。

4. EXPLAIN FOR

达梦还提供更加详细的:

sql 复制代码
EXPLAIN FOR
SELECT *
FROM EMPLOYEE
WHERE DEPT_ID = 10;

普通 EXPLAIN 通常以树形文本显示计划,而 EXPLAIN FOR 会以结构化结果集的形式返回信息。

除了操作符、表名、索引名、预计行数和代价外,还可以包含:

  • 扫描类型;
  • 扫描范围;
  • CPU 代价;
  • I/O 代价;
  • 过滤条件;
  • 连接条件;
  • 分区扫描范围;
  • 索引建议;
  • 其他扩展计划信息。

EXPLAIN FOR 还可用于查看相关 DML 语句的计划,适合需要保存、比较或进一步分析计划字段的场景。

可以简单区分为:

text 复制代码
EXPLAIN:
适合快速阅读执行计划树。

EXPLAIN FOR:
适合查看更完整、更结构化的计划信息。

5. EXPLAIN 最适合解决的问题

EXPLAIN 最适合用于快速判断:

  • 是否使用了预期索引;
  • 是否出现不合理的大表扫描;
  • 是否存在大量回表的可能;
  • 表连接顺序是否符合数据规模;
  • 为什么选择嵌套循环或哈希连接;
  • SQL 改写后计划是否发生变化;
  • 创建或删除索引后访问路径是否变化;
  • 统计信息变化是否影响优化器估算。

但 EXPLAIN 主要用于发现"可能存在的问题",不能单独作为最终性能结论。


五、AUTOTRACE:查看实际执行计划与整体资源消耗

EXPLAIN 反映的是优化器的预估。如果需要知道 SQL 真正执行时采用了什么计划、读取了多少数据、发生了多少 I/O,就需要使用 AUTOTRACE。

AUTOTRACE 是 disql 中用于控制执行计划和统计信息跟踪方式的环境变量,语法如下:

sql 复制代码
SET AUTOTRACE
<OFF | NL | INDEX | ON | TRACE | TRACEONLY>;

不同模式并不是简单的显示格式差异,其中最重要的区别是:有些模式不会真正执行 SQL,有些模式会真正执行 SQL。

1. OFF:关闭跟踪

sql 复制代码
SET AUTOTRACE OFF;

关闭 AUTOTRACE,后续 SQL 按普通方式执行。

这是缺省状态。

2. NL:只观察嵌套循环信息

sql 复制代码
SET AUTOTRACE NL;

该模式不会真正执行目标 SQL。

如果计划中存在嵌套循环,则主要显示与 NEST LOOP 有关的内容,适合快速观察:

  • 是否使用嵌套循环;
  • 嵌套循环大致位于计划的什么位置;
  • 哪些节点参与嵌套循环。

但它不会提供完整执行统计,也不能反映真实耗时。

3. INDEX 或 ON:快速查看访问路径

sql 复制代码
SET AUTOTRACE INDEX;

或者:

sql 复制代码
SET AUTOTRACE ON;

这两种模式也不会真正执行 SQL,主要显示:

  • 表扫描方式;
  • 表名;
  • 使用的索引。

它们适合快速回答:

这条 SQL 查哪些表,使用了哪些索引?

需要注意,达梦中的 AUTOTRACE ON 主要用于查看扫描方式和索引信息,不能直接等同于其他数据库中"执行 SQL 并输出完整统计"的 AUTOTRACE ON。

4. TRACE:真正执行并显示结果

sql 复制代码
SET AUTOTRACE TRACE;

设置完成后执行 SQL,数据库会:

  • 真正执行目标 SQL;
  • 返回查询结果;
  • 显示服务器实际采用的执行计划;
  • 显示本次执行的部分资源统计信息。

AUTOTRACE TRACE 和 EXPLAIN 的核心区别是:

text 复制代码
EXPLAIN:
不执行SQL,看到的是优化器预估计划。

AUTOTRACE TRACE:
真正执行SQL,看到的是服务器实际采用的计划。

实际计划可能是本次新生成的,也可能来自数据库已有的计划缓存。因此,当管理工具中手工 EXPLAIN 的结果与应用程序实际执行表现不一致时,实际计划通常更具有排查价值。

5. TRACEONLY:真正执行但不输出查询结果

sql 复制代码
SET AUTOTRACE TRACEONLY;

TRACEONLY 与 TRACE 的执行过程基本一致,也会:

  • 真正执行 SQL;
  • 显示实际执行计划;
  • 收集资源统计信息。

区别是,对于查询语句,TRACEONLY 不会把结果集打印到客户端。

这对于返回大量数据的 SQL 很重要。假设一条查询返回 50 万行,如果使用 TRACE,大量时间可能消耗在:

  • 服务器向客户端传输数据;
  • 客户端接收数据;
  • 终端格式化和显示结果。

此时 SQL 的业务执行耗时和结果输出耗时会混在一起,不便于分析。使用 TRACEONLY 可以减少终端输出带来的干扰。

但必须明确:

TRACEONLY 只是"不显示查询结果",并不是"不执行 SQL"。

如果目标语句是:

sql 复制代码
UPDATE ...
DELETE ...
INSERT ...

数据仍然可能被真正修改。因此,分析 DML 时应在测试环境操作,或明确控制事务。

6. AUTOTRACE 输出中的实际行数

预估计划的节点通常显示类似:

text 复制代码
[代价, 预计行数, 行长度]

实际计划中则可能出现预计值与实际值的对比,例如带有箭头的行数信息:

text 复制代码
[代价, 预计行数 -> 实际行数, 行长度]

如果出现:

text 复制代码
100 -> 100

说明优化器预计与实际较接近。

如果出现:

text 复制代码
10 -> 200000

说明优化器严重低估了该节点的数据量。

这种差异非常值得关注,因为它可能导致:

  • 错误选择嵌套循环;
  • 选择不合适的驱动表;
  • 错误判断索引访问成本;
  • 哈希表或排序空间估算不足;
  • 中间结果集明显膨胀。

因此,AUTOTRACE 不只是为了看 SQL 执行了多少毫秒,还可以帮助验证优化器估算是否准确。

7. AUTOTRACE 统计信息怎样理解

TRACE 或 TRACEONLY 可以显示部分执行统计,常见指标包括以下内容。

logical reads

逻辑读表示数据库访问缓冲区中数据页的次数。

逻辑读较高,通常说明 SQL 处理的数据量较大,可能存在:

  • 大范围表扫描;
  • 大范围索引扫描;
  • 大量回表;
  • 嵌套循环反复读取;
  • 连接产生大量中间结果;
  • 过滤条件生效过晚。

逻辑读发生在内存中,不等于磁盘读取,但逻辑读过多仍会消耗 CPU 和内存访问资源。

在比较两种 SQL 或两份计划时,逻辑读往往比单次执行时间更稳定、更具有参考价值。

physical reads

物理读表示需要从磁盘或存储设备加载数据页。

物理读较高可能说明:

  • 查询数据尚未进入缓存;
  • 扫描范围很大;
  • 缓冲区缓存不足;
  • 数据页被其他负载挤出;
  • 当前测试属于冷缓存执行。

同一条 SQL 第一次执行和第二次执行的物理读可能明显不同,因此不能只根据一次执行结果判断优化效果。

sorts (memory)

表示排序在内存中完成。

出现内存排序并不一定有问题,因为 ORDER BYGROUP BYDISTINCT 和部分连接操作本来就需要排序。

需要结合排序的数据量和执行耗时判断。

sorts (disk)

表示排序过程中使用了磁盘临时空间。

磁盘排序通常比内存排序开销更大。如果该指标出现,需要进一步检查:

  • 排序前的数据是否过多;
  • 能否让过滤条件更早执行;
  • 是否存在不必要的排序或去重;
  • 是否可以利用索引有序性;
  • 内存配置是否适合当前数据规模。
rows processed

表示 DML 语句处理或影响的记录数。

如果 UPDATE 预计只修改几十行,实际却处理几十万行,需要检查 WHERE 条件和访问路径。

redo size、data pages changed 和 undo pages changed

这些指标主要用于观察 DML 的修改量。

一次大批量更新可能产生:

  • 大量数据页修改;
  • 大量 UNDO;
  • 大量 REDO 日志。

此时 SQL 慢的原因可能不仅是查询路径,还包括日志写入、事务规模和存储 I/O。

roundtrips to/from client

表示客户端与服务器的交互次数。

如果应用程序循环执行大量单条 SQL,或者每次只读取很少的数据,网络往返次数可能成为额外负担。

io wait time 与 exec time

io wait time 表示 I/O 等待时间,exec time 表示执行耗时。

如果执行时间高且 I/O 等待占比也高,问题可能集中在:

  • 数据读取量过大;
  • 物理存储性能;
  • 缓存命中不足;
  • 大量临时空间读写;
  • 日志写入。

如果执行时间很高但 I/O 等待较低,则还要关注:

  • 大量逻辑读;
  • CPU 计算;
  • 排序和哈希;
  • 操作符重复执行;
  • 复杂表达式或函数。

8. 使用 AUTOTRACE 时的监控条件

要获得较完整的实际执行统计,需要开启相关监控参数,例如:

text 复制代码
ENABLE_MONITOR
MONITOR_SQL_EXEC
ENABLE_MONITOR_DMSQL

其中,MONITOR_SQL_EXEC 可以按会话开启,用于记录操作符和执行计划节点统计;ENABLE_MONITOR_DMSQL 也可用于动态 SQL 执行时间监控。详细监控会增加一定开销,因此更适合在指定分析会话中临时开启,而不是在生产系统长期全局启用。

9. AUTOTRACE 使用场景

AUTOTRACE 适合进一步确认:

  • 实际计划是否与 EXPLAIN 计划一致;
  • 优化器预计行数与实际行数差异多大;
  • SQL 的逻辑读和物理读是否过高;
  • 是否发生磁盘排序;
  • 查询结果传输是否影响总耗时;
  • DML 是否产生大量日志和数据页修改;
  • 优化前后实际资源消耗是否下降。

AUTOTRACE 提供的是整条 SQL 和整份计划的总体情况。如果要进一步精确到"究竟是哪一个操作符最慢",还需要使用 ET。


六、ET:定位执行计划中的真实耗时节点

AUTOTRACE 可以告诉我们整条 SQL 执行了多长时间、读取了多少数据页,但一份复杂执行计划可能包含十几个甚至几十个节点。

例如 SQL 总执行时间为 8 秒,仅凭这个结果仍然不能确定:

  • 是表扫描用了 8 秒;
  • 是排序用了 8 秒;
  • 是某个哈希连接耗时;
  • 还是嵌套循环中的右侧节点被重复调用了几十万次。

ET 的作用,就是把一次 SQL 执行拆解到各个操作符,查看每个节点实际消耗的时间和资源。

1. ET 分析的是"某一次执行"

ET 不是直接接收 SQL 文本,而是接收 SQL 的执行号:

sql 复制代码
ET(执行号);

例如:

sql 复制代码
ET(843);

这里的执行号代表 SQL 的某一次具体执行。

即使 SQL 文本完全相同,两次执行也可能有不同的执行号。这样 ET 可以区分:

  • 第一次执行;
  • 第二次执行;
  • 不同参数值下的执行;
  • 优化前和优化后的执行。

因此,ET 分析的是:

某一条 SQL 在某一次真实执行中的操作符耗时。

而不是一份静态的预估执行计划。

2. ET 与 EXPLAIN、AUTOTRACE 的区别

三者可以这样理解:

text 复制代码
EXPLAIN:
显示优化器预估的计划结构。

AUTOTRACE:
显示实际计划和整条SQL的总体资源消耗。

ET:
显示这次执行中每个操作符分别消耗了多少时间。

假设 AUTOTRACE 显示:

text 复制代码
exec time = 5000ms

ET 可能进一步显示:

text 复制代码
CSCN2       3600000us
HASH JOIN    900000us
SORT         400000us
其他节点      100000us

这样就能确认主要耗时集中在扫描节点,而不是排序或连接节点。

3. 使用 ET 需要的监控信息

ET 依赖 SQL 操作符监控,通常需要开启:

text 复制代码
ENABLE_MONITOR
MONITOR_TIME
MONITOR_SQL_EXEC

其中 MONITOR_SQL_EXEC 可以设置为会话级,只采集当前会话的操作符统计。

如果监控参数未开启,SQL 虽然可以正常执行,但 ET 可能无法取得对应的节点耗时信息。

4. ET 输出中的核心字段

ET 输出的字段较多,初学阶段应重点关注以下几项。

OP

表示操作符名称,例如:

text 复制代码
CSCN2
SSEK2
BLKUP2
HASH JOIN
SORT
PRJT2

同一份计划中可能出现多个相同操作符,因此不能只根据 OP 判断具体是哪个节点。

TIME(US)

表示该操作符的实际执行耗时,单位为微秒。

这是定位瓶颈最直接的字段。

一般先按耗时从高到低查看,优先分析 TIME 最大的几个节点。

但需要注意,某些上层节点的时间可能包含等待下层节点返回数据的时间。因此,不能只看单个数字,还要结合计划树的父子关系判断。

PERCENT

表示操作符耗时在整个计划中的占比。

例如:

text 复制代码
PERCENT = 82%

说明该节点消耗了大部分执行时间,通常是最优先分析的对象。

如果一个节点耗时比例很高,可以继续判断它属于:

  • 表扫描;
  • 索引扫描;
  • 回表;
  • 连接;
  • 排序;
  • 聚合;
  • 数据输出。
RANK

表示节点的耗时排名。

ET 通常会将节点按耗时从高到低排列,RANK 可以帮助快速找到最耗时的节点。

SEQ

表示该操作符在执行计划中的节点序号。

这是 ET 与执行计划建立对应关系的关键字段。

例如执行计划中存在:

text 复制代码
4  #CSCN2: DEPARTMENT
7  #CSCN2: EMPLOYEE

ET 显示:

text 复制代码
OP=CSCN2
SEQ=7
PERCENT=80%

就可以确定真正耗时的是 EMPLOYEE 的扫描,而不是 DEPARTMENT

因此,分析 ET 时不能只说"CSCN2 很慢",应准确到:

执行计划中编号为 7、访问 EMPLOYEE 表的 CSCN2 节点耗时最高。

N_ENTER

表示操作符被进入或调用的次数。

这是 ET 中非常重要、但容易被忽略的字段。

例如某个索引扫描:

text 复制代码
SSEK2
TIME(US)=3000000
N_ENTER=500000

说明该索引扫描节点被调用了 50 万次。

这种情况经常出现在嵌套循环中:

text 复制代码
NEST LOOP
  左侧节点返回50万行
  右侧SSEK2被调用50万次

每次索引定位可能只需要很短时间,但累计执行 50 万次后,整体耗时仍然很高。

此时,问题的根源可能不是索引本身慢,而是:

  • 左侧结果集过大;
  • 驱动表选择不合理;
  • 过滤条件没有提前生效;
  • 连接顺序不合理;
  • 优化器预计行数严重偏小;
  • 当前数据规模不适合嵌套循环。
MEM_USED(KB)

表示操作符使用的内存空间。

对于哈希连接、排序和聚合等操作,可以通过该字段观察节点的内存使用情况。

DISK_USED(KB)

表示操作符使用的磁盘空间。

如果排序、哈希或聚合节点使用了较多磁盘空间,通常说明:

  • 中间数据量较大;
  • 内存空间不足;
  • 操作发生了磁盘溢写;
  • 过滤和数据缩减发生得太晚。

ET 还可以显示哈希表槽位、哈希冲突等更深入的信息,适合进一步分析哈希连接和哈希聚合,但入门阶段不必立即展开。

5. 怎样根据 ET 判断常见问题

扫描节点耗时最高

例如:

text 复制代码
CSCN2
PERCENT=85%

说明时间主要花在表数据扫描上。

需要继续检查:

  • 扫描的表有多大;
  • WHERE 条件能否提前过滤;
  • 是否缺少合适索引;
  • 查询是否本来就需要返回大量数据;
  • 预计行数与实际行数是否一致。

不能看到 CSCN2 就直接认定必须创建索引。如果 SQL 返回大部分数据,全表扫描可能仍然合理。

回表节点耗时较高

例如:

text 复制代码
BLKUP2
PERCENT=70%

说明数据库虽然使用了二级索引,但大量时间消耗在回表获取其他列。

可能原因包括:

  • 索引返回记录过多;
  • 查询字段较多;
  • 索引选择性较差;
  • 数据页访问较分散;
  • 索引虽然被使用,但并不适合当前查询。
索引节点 N_ENTER 很高

例如:

text 复制代码
SSEK2
N_ENTER=300000

通常需要检查该节点是否处于嵌套循环右侧。

优化方向可能包括:

  • 减少左侧结果集;
  • 调整连接顺序;
  • 更新统计信息;
  • 判断哈希连接是否更合适;
  • 优化连接条件和过滤条件。
SORT 节点磁盘使用较高

如果排序节点的 DISK_USED(KB) 较大,说明排序过程中可能使用了磁盘临时空间。

需要检查:

  • 是否存在不必要的 ORDER BY
  • 是否存在重复的 DISTINCT
  • 排序前是否可以减少数据量;
  • 是否可以利用索引顺序;
  • 内存配置是否合理。
哈希节点耗时或内存使用较高

如果哈希连接或哈希聚合耗时明显,需要检查:

  • 建立哈希表的一侧是否过大;
  • 优化器是否错误选择了构建侧;
  • 实际行数是否远大于预计行数;
  • 哈希表是否发生大量冲突;
  • 是否使用了磁盘空间。

6. ET 为什么可能出现 EXPLAIN 中没有的操作符

ET 反映的是实际执行过程,可能出现预估 EXPLAIN 中没有直接显示的节点。

官方文档指出,某些实际执行中的内部操作符,例如用于字典对象加锁的 DLCK,可能出现在 ET 中,但不会出现在普通 EXPLAIN 计划里。

此外,如果目标 SQL 触发了:

  • 触发器;
  • 内部函数;
  • 约束检查;
  • 级联操作;
  • 数据字典访问;

ET 中也可能出现与 SQL 主计划之外相关的操作符。

因此,不能看到额外节点就立即判断 ET 结果错误。需要先确认 SQL 是否触发了其他内部执行过程。

7. 为什么有些 EXPLAIN 节点没有出现在 ET 中

官方文档也说明,如果某些操作符:

  • 实际没有被执行;
  • 执行时间非常短;
  • 没有形成可记录的统计;

它们可能不会出现在 ET 结果中。

因此,ET 不是简单复制 EXPLAIN 后再附加时间,而是展示实际执行中被监控并产生有效统计的节点。

8. ET 没有结果时怎样排查

如果输入执行号后 ET 没有返回有效信息,可以检查:

  • ENABLE_MONITOR 是否开启;
  • MONITOR_TIME 是否开启;
  • MONITOR_SQL_EXEC 是否在 SQL 执行前开启;
  • 使用的是否为正确执行号;
  • 查询结果是否已经被完整处理;
  • 当前用户是否有执行 ET 的权限;
  • 监控信息是否已经被后续大量执行覆盖。

普通用户没有权限时,可以由管理员按最小权限原则授权:

sql 复制代码
GRANT EXECUTE ON SYS.ET TO 用户名;

ET 分析应尽量在目标 SQL 执行完成后及时进行,避免监控数据发生变化。

9. ET 适合的场景

ET 最适合用来查看:

  • 一份复杂计划中哪个节点最耗时;
  • 是否存在某个节点被重复调用大量次数;
  • 索引扫描慢,还是回表慢;
  • 扫描、排序、连接和聚合各自消耗多少;
  • 哈希或排序是否使用较多内存、磁盘;
  • 实际瓶颈是否与 EXPLAIN 中的高代价节点一致;
  • 优化前后高耗时节点是否真正下降。

因此,ET 的价值不只是"显示操作符时间",而是把性能问题从"这条 SQL 很慢"进一步缩小到:

执行计划中的哪一个节点慢,它为什么慢,以及下一步应分析什么。

七、三个工具怎样配合

EXPLAIN、AUTOTRACE 和 ET 的关系可以概括为:

text 复制代码
EXPLAIN
查看预估计划

AUTOTRACE
查看实际计划和整体资源消耗

ET
查看每个操作符的实际耗时

分析一条慢 SQL 时,可以按照以下思路进行:

text 复制代码
发现SQL较慢
→ 使用EXPLAIN查看扫描、索引和连接方式
→ 使用AUTOTRACE查看实际计划和资源消耗
→ 使用ET定位耗时最高的节点
→ 再决定是否调整SQL、索引或统计信息

这里最重要的是,不要在没有分析计划的情况下直接创建索引,也不要只凭一次执行时间判断优化是否有效。

八、总结

达梦数据库 SQL 性能分析的核心,不是记住多少操作符,而是建立正确的分析顺序。

首先看执行计划,确认数据库选择了什么扫描方式、索引和连接方式;然后通过实际执行统计,观察 SQL 读取了多少数据、进行了多少排序、消耗了多少时间;最后再定位具体的高耗时操作符。

三个工具的分工非常明确:

text 复制代码
EXPLAIN:数据库准备怎么执行
AUTOTRACE:数据库实际上怎么执行
ET:执行时间主要花在哪里
相关推荐
爬也要爬着前进5 小时前
redis主从搭建
数据库·redis·缓存
@Mike@5 小时前
02-数据库学习笔记(SQL引擎)
数据库·笔记·学习
keyipatience6 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
笃行3506 小时前
国产化落地避坑 · 干货向|Oracle 迁金仓 KES,我把外连接消除排在隐性陷阱第一位
数据库
老纪的技术唠嗑局6 小时前
花一年时间整理出的:AI 数据库混合搜索入门实践
数据库
星夜夏空997 小时前
网络编程(1)
服务器·网络
川石课堂软件测试7 小时前
安全测试|常见SQL注入攻击方式、实例及预防
服务器·数据库·sql·功能测试·测试工具·安全·单元测试
笃行3507 小时前
国产化落地避坑 · 干货向|迁移后那条「测试能过、一上生产就查空」的 SQL,多半栽在 WHERE 函数顺序上
数据库
蓝田~8 小时前
MySQL慢查询怎么优化?B+Tree索引原理+MVCC读不阻塞写+EXPLAIN执行计划,从5秒到0.05秒
数据库·mysql