注册
达梦数据库sql优化入门之如何读懂执行计划\Statistics\ET
专栏/技术分享/ 文章详情 /

达梦数据库sql优化入门之如何读懂执行计划\Statistics\ET

dm-9527 2026/10/23 72 0 0
摘要

作为刚接触sql优化的小白,需要尽快掌握的能力就是如何阅读执行计划树、核对实际行数、分析总体资源消耗,再用 ET 定位操作符开销。本文保留原始性能数字;数据库版本、原始 SQL、绑定值和表结构未提供,因此对内部标记和运行机制的解释会区分确定事实与待验证推断。

1. 案例结论

​ 表统一表示为 TABLE_A、TABLE_B,索引统一表示为 IDX_A_01、IDX_B_01;业务表引用别名统一表示为 B,数据库生成的临时视图统一表示为 TEMP_VIEW_01。此外替换了业务标识常量和执行号。本文不附原名映射,避免文章重新暴露原始名称。列名、年度、期间边界和运行指标保留,以便解释条件与访问路径;这不是对所有业务信息的完全匿名化。

这份记录支持以下结论:

  • TABLE_A 一侧估算输出 1 行,实际输出 0 行。
  • 右侧 TABLE_B 的索引定位和回表节点进入次数为 0,未执行。
  • Statistics 显示逻辑读 93 次,物理读、直接物理读和 I/O 等待均为 0。
  • ET 列出的节点耗时合计 182 微秒,即 0.182 毫秒;Statistics 的执行耗时为 6.457 毫秒;末尾客户端显示 599.422 毫秒,三者不是同一统计口径。
  • 这是一份空结果执行样本,不能据此证明右侧索引、高数据量连接或排序聚合已经得到充分验证。

2. 三类信息分别回答什么问题

信息 回答的问题 分析边界
执行计划 访问哪些对象,采用什么扫描、连接、聚合和排序方式 预估计划不能证明实际执行情况;本例附带实际行数和计时
Statistics 本次执行消耗了多少读、写、传输与时间资源 总体指标不能直接分摊到某个表或索引
ET 哪些操作符被调用,各自记录了多少时间、内存和磁盘空间 操作符计时不能直接代替完整请求耗时

普通 EXPLAIN 用于查看预估方案;实际跟踪还可以给出实际行数、进入次数和耗时。代价三元组的基础定义见官方《查询优化》。

3. 执行计划

################################################################################################################################################################################################
1   #NSET2: [2, 1->0, 450] ; used times:0.104(ms); n_enter:2
2     #PRJT2: [2, 1->0, 450]; exp_num(26), is_atom(FALSE); INFO_BITS(0); used times:0.002(ms); n_enter:2
3       #SORT3: [2, 1->0, 450]; key_num(2), partition_key_num(0), is_distinct(FALSE), is_adaptive(0), MEM_USED(18416KB), DISK_USED(0KB); used times:0.011(ms); n_enter:2
4         #HAGR2: [1, 1->0, 450]; grp_num(2), sfun_num(18), MEM_USED(0KB), DISK_USED(0KB), distinct_flag[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; slave_empty(0) keys(TEMP_VIEW_01.TMPCOL0, TEMP_VIEW_01.TMPCOL1); opt_info_bits(0); used times:0.006(ms); n_enter:2
5           #PRJT2: [1, 1->0, 450]; exp_num(20), is_atom(FALSE); INFO_BITS(0); used times:0.001(ms); n_enter:2
6             #SLCT2: [1, 1->0, 450]; B.VOUCHERKIND <> var8, slct_pushdown(0); used times:0.005(ms); n_enter:2
7               #NEST LOOP INDEX JOIN2: [1, 1->0, 450] ; used times:0.002(ms); n_enter:2
8                 #SSCN: [1, 1->0, 48]; IDX_A_01(TABLE_A); btr_scan(1); is_global(0); used times:0.041(ms); n_enter:1
9                 #BLKUP2: [1, 1, 192]; IDX_B_01(TABLE_B); use_clu_addr(0); used times:0(ms); n_enter:0
10                  #SLCT2: [1, 1, 192]; (B.PK_ACCOUNTINGBOOK = 'BOOK_ID_001' AND B.YEAR = '2025' AND B.ADJUSTPERIOD >= '00' AND B.ADJUSTPERIOD <= '12A'), slct_pushdown(0); used times:0(ms); n_enter:0
11                    #SSEK2: [1, 1, 192]; scan_type(ASC), IDX_B_01(TABLE_B), is_global(0), scan_range[(TABLE_A.PK_ACCASOA,min,min,min,min),(TABLE_A.PK_ACCASOA,max,max,max,max)); used times:0(ms); n_enter:0
################################################################################################################################################################################################
Statistics
-----------------------------------------------------------------
	0                   	    data pages changed
	0                   	    undo pages changed
	93                  	    logical reads
	0                   	    physical reads
	0                   	    direct physical reads
	0                   	    redo size
	1671                	    bytes sent to client
	6940                	    bytes received from client
	2                   	    roundtrips to/from client
	0                   	    sorts (memory)
	0                   	    sorts (disk)
	0                   	    rows processed
	0.000               	    io wait time(ms)
	6.457               	    exec time(ms)
################################################################################################################################################################################################
行号     OP    TIME(US)             PERCENT RANK                 SEQ         N_ENTER     MEM_USED(KB)         DISK_USED(KB)        HASH_USED_CELLS      HASH_CONFLICT        DHASH3_USED_CELLS DHASH3_CONFLICT HASH_SAME_VALUE      INFO1
---------- ----- -------------------- ------- -------------------- ----------- ----------- -------------------- -------------------- -------------------- -------------------- ----------------- --------------- -------------------- -----
1          PRJT2 1                    .55%    9                    5           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
2          IJI2  2                    1.1%    7                    7           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
3          PRJT2 2                    1.1%    7                    2           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
4          SLCT2 5                    2.75%   6                    6           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
5          HAGR2 6                    3.3%    5                    4           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
6          DLCK  10                   5.49%   4                    0           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
7          SORT3 11                   6.04%   3                    3           2           18416                0                    0                    0                    NULL              NULL            0                    NULL
8          SSCN  41                   22.53%  2                    8           1           0                    0                    0                    0                    NULL              NULL            0                    NULL
9          NSET2 104                  57.14%  1                    1           2           0                    0                    0                    0                    NULL              NULL            0                    NULL
9 rows got
已用时间: 599.422(毫秒). 执行号:EXEC_ID_001.
SQL>```

上述代码块同时保留了 Statistics 和 ET 原始排列,便于下文交叉核对。`EXEC_ID_001` 是文本占位符,不是可以直接传给 ET 的数值执行号。

## 4. 第一步:先拆解一行执行计划

以排序节点为例:

```text
3 #SORT3: [2, 1->0, 450]; key_num(2), ...;
  MEM_USED(18416KB), DISK_USED(0KB);
  used times:0.011(ms); n_enter:2
部分 含义 本例解读
3 计划节点序号 用来与 ET 的 SEQ=3 对应
缩进 父子关系 SORT3 的下层输入来自 HAGR2
#SORT3 操作符 排序;尾部数字属于操作符名称,不是次数
三元组第一项 2 优化器估算代价 用于比较候选方案,不能当成实测 2 毫秒
第二项 1->0 此类实际计划中的估算行数→实际输出行数 预计 1 行,实际 0 行
第三项 450 估算的单行记录字节数 不是总输出 450 字节,也不是网络包大小
used times 节点记录的耗时,单位毫秒 0.011 毫秒等于 ET 的 11 微秒
n_enter 操作符进入次数 2 次进入不代表返回 2 行

没有箭头不等于实际行数等于估算值。例如节点 9~11 保留 [1, 1, 192],但进入次数为 0,不能说它们实际处理了 1 行。

5.沿数据流阅读计划树

计划树描述的是数据依赖。阅读时从下层数据来源向上理解,但执行器会由上层请求下层数据;嵌套循环还会反复进入右侧分支,不能把整棵树看成只运行一遍的固定行号顺序。

本例的设计路径可以简化为:

TABLE_A 二级索引扫描(SSCN,节点8)
  ↓ 每取得一条驱动记录,就尝试右侧索引连接
TABLE_B 索引定位(SSEK2,节点11)
  ↓ 过滤账簿、年度和期间(SLCT2,节点10)
  ↓ 回表取需要的记录(BLKUP2,节点9)
索引嵌套循环连接(节点7)
  ↓ 过滤类别(节点6)
  ↓ 计算20项表达式(节点5)
  ↓ 按2项分组、计算18项聚合(节点4)
  ↓ 按2项排序(节点3)
  ↓ 计算26项输出表达式(节点2)
  ↓ 收集结果(节点1)

这里的流程图表示计划结构;实际运行时,节点 8 没有输出数据,右侧节点 9~11 完全没有启动。对节点 10 所需列是否由索引覆盖,应查看索引定义,不能仅凭其位于回表节点下方补写出索引列清单。

5.1 节点 8:驱动侧扫描

#SSCN: [1, 1->0, 48]; IDX_A_01(TABLE_A);
       btr_scan(1); is_global(0);
       used times:0.041(ms); n_enter:1

SSCN 表示二级索引扫描,与根据键值定位范围的 SSEK2 区别开。它不自动意味着低效,也不等于扫描业务表全部数据页。本例耗时 41 微秒,实际输出为 0。

优先检查驱动数据是否按预期准备、是否处于同一会话和事务、前序处理是否完成、查询条件是否对应当前样本。表名脱敏后不能从 TABLE_A 判断它一定是临时表;应以 DDL 为准。

5.2 节点 7、9~11:索引连接与未执行的右侧分支

NEST LOOP INDEX JOIN2 表示使用索引的嵌套循环连接;ET 中对应缩写 IJI2。通常左侧每提供一条记录,就用其中的键值探测右侧索引。

本例右侧 SSEK2 的范围由 TABLE_A.PK_ACCASOA 驱动,随后还有过滤和回表。可确定这些操作存在于计划中,但它们的 n_enter=0、耗时为 0,因此没有测到其真实开销。零耗时还要与进入次数一起看:单独的 0(ms) 也可能与计时精度有关。

5.3 节点 6:连接后的残余过滤

B.VOUCHERKIND <> var8

var8 是计划显示的变量占位;不能仅凭名字确认它等于应用端第八个绑定参数,也不能恢复其值。分析时需核对实际值及数据类型,尤其要注意 NULL:SQL 中与 NULL 的普通不等比较不会得到 TRUE。

slct_pushdown(0) 表示该节点未采用对应的过滤下推优化标记,不能据此断言整条 SQL 所有条件都未下推,也不能直接推出“应强制下推”。

5.4 节点 4:分组聚合

HAGR2 是哈希分组聚合。此处有两个分组项、18 个聚合函数项;分组列显示为优化器中间结果的 TEMP_VIEW_01.TMPCOL0 和 TMPCOL1。这些名字不能直接还原成原 SQL 的分组表达式。

本例输入为空且存在分组,实际没有分组输出。这与不带 GROUP BY 的单组 COUNT(*) 可能返回一条计数为 0 的记录不同。

5.5 节点 3:排序

计划存在 SORT3,内存记账 18416 KB,磁盘记账 0 KB,耗时 11 微秒。按 1024 换算,18416 KB 约为 17.98 MiB。

虽然实际没有输出行,排序结构仍可能在初始化阶段申请或登记空间;仅凭这里的字段,不能确定该值就是实际有效数据体积、进程常驻内存增量或可立刻回收的内存。Statistics 中内存排序次数为 0,也不与“计划存在排序节点”构成矛盾:计划结构、节点内存记账和实际排序次数是不同观测维度。

6. 计划中各项附加参数的含义

以下参数定义以官方《附录4:执行计划操作符》为基础;内部标记需匹配具体版本。

参数 含义与本例解释
exp_num(26) / exp_num(20) 投影表达式数量;可含计算项或中间项,不能机械等同于业务表物理列数
is_atom(FALSE) 不要求单行数据;与事务是否原子无关
INFO_BITS(0) 投影相关优化位标记为 0;不表示数据库所有优化都关闭
key_num(2) SORT3 的排序项数量为 2
partition_key_num(0) 已有序的前导排序列数量为 0;不是表分区数为 0
is_distinct(FALSE) 此排序不承担去重
is_adaptive(0) 未使用该排序节点的自适应优化;不能代表系统自适应功能总开关
MEM_USED / DISK_USED 节点记录的内存和磁盘空间,单位 KB;不是读写次数
grp_num(2) 分组表达式数量为 2
sfun_num(18) 向上层提供的聚合函数项数量为 18
distinct_flag[...] 各聚合函数参数是否去重;本例18项均为0
slave_empty(0) 未限制相关 MPP 从节点或本地并行从线程向上层传数据;不能证明启用了并行
keys(...) 分组项;本例为中间投影列
opt_info_bits(0) 聚合相关内部优化标记;缺少版本定义时不展开位语义
slct_pushdown(0) 当前过滤节点的过滤下推优化标记为0
btr_scan(1) 使用 B 树扫描方式;0 对应簇游标扫描方式
is_global(0) 未使用全局索引;不能据此判断表是否分区
use_clu_addr(0) 未采用从二级索引记录读取聚集记录地址的对应定位优化;仍然是回表节点
scan_type(ASC) 索引按升序方向扫描;不等于最终结果满足 ORDER BY
scan_range[...] 索引扫描的键值边界;需结合索引列序理解
min / max 内部范围边界标记,不是执行了 SQL 的 MIN/MAX 聚合
used times 节点计时;与 Statistics 的总耗时分开分析
n_enter 进入次数,不是实际输出行数,也不是物理读次数

6.1 如何看复合索引的 scan_range

本例范围为:

[(TABLE_A.PK_ACCASOA,min,min,min,min),
 (TABLE_A.PK_ACCASOA,max,max,max,max))

直观含义是:按驱动记录给出的键值固定前导范围,后面的键分量取较宽边界。括号描述内部复合键边界,不宜直接改写为某个业务期间条件。

范围里没有直接出现账簿、年度和期间常量,而这些条件显示在 SLCT2 中。这提示我们:若有数据时右侧探测范围很大,应检查复合索引列顺序,以及这些过滤条件能否参与更精确的索引定位。还需核对隐藏定位键、索引定义和完整 SQL,不能单凭边界分量数断言“这是恰好五个业务列的索引”。

7. 第三步:逐项阅读 Statistics

Statistics 是本次执行的运行统计,不是优化器使用的表行数、直方图等“统计信息”。两者用途不同。

指标 本例值 含义 分析方法
data pages changed 0 修改的数据页计数 与写操作相关;不是影响行数
undo pages changed 0 修改的 undo 页计数 观察回滚信息相关写入
logical reads 93 逻辑页访问次数,重复访问可能重复计数 不是93条记录,也不一定是93个不同页
physical reads 0 统计到的普通物理页读取 本次没有该类读取,不代表表没有数据
direct physical reads 0 统计到的直接路径物理页读取 与普通物理读分开观察
redo size 0 统计到的重做日志量,通常按字节表示 不等同于全实例日志文件增长量
bytes sent to client 1671 服务器向客户端发送字节数 含协议、元数据等,不全是结果行
bytes received from client 6940 服务器收到的客户端字节数 不能等同于 SQL 文本长度
roundtrips to/from client 2 客户端与服务器往返计数 不是返回2行,也不是一定新建2次连接
sorts (memory) 0 计入统计的内存排序次数 不等于没有SORT节点或内存分配
sorts (disk) 0 计入统计的磁盘排序次数 与节点DISK_USED结合检查落盘
rows processed 0 本语句统计口径下处理的行数 对本例查询与最终输出0行相符,不能当成所有节点累计处理行数
io wait time(ms) 0.000 统计到的I/O等待毫秒数 不能直接排除锁、调度、网络等其他等待
exec time(ms) 6.457 此统计口径下的执行毫秒数 与客户端请求全过程及ET节点时间分开

7.1 本例应该怎么推理

先看结果量:最终 0 行。再看读取:逻辑读 93,物理读及直接物理读为 0,本次统计不到磁盘读取压力。即使没有返回行,访问索引结构、元数据或执行初始化仍可能产生逻辑读;这里没有足够信息把93次全部归到节点8。

再看写入与排序:数据页、undo、redo和磁盘排序均为0,没有这些指标上的资源压力证据。最后看传输:空结果也存在协议和元数据传输,因此1671字节与返回0行并不矛盾。

不能仅由“物理读为0”推导出一个精确缓存命中率,也不能把93乘以某个未经核实的页大小当成唯一工作集大小。

8. 第四步:用 ET 对应节点、解释列并定位开销

ET 按执行号统计操作符开销,官方定义及字段说明见《附录:ET》。

ET列 含义 阅读要点
行号 查询输出的行序 不是计划节点号
OP 操作符名称或缩写 同一OP可能出现多次
TIME(US) 记录的执行耗时,微秒 1000微秒=1毫秒
PERCENT 节点用时在计划计时中的占比 本例分母可由数字核算为182微秒
RANK 耗时排名,1为最大 相同耗时可以并列
SEQ 计划节点序号 用它定位计划中的具体节点
N_ENTER 操作符进入次数 初始化、取数、结束等调用与实现有关,不等于行数
MEM_USED(KB) 操作符内存空间记账 留意并发下多个节点的总体需求
DISK_USED(KB) 操作符磁盘空间记账 不是I/O耗时或读写次数
HASH_USED_CELLS 哈希表使用槽数 结合输入量与冲突看
HASH_CONFLICT 存在哈希冲突的记录数 不等于业务重复记录数量
DHASH3_USED_CELLS 动态哈希表使用槽数 NULL通常表示未提供或不适用,不能直接替成0
DHASH3_CONFLICT 动态哈希表冲突情况 具体细节结合版本
HASH_SAME_VALUE 启用相同值挂链优化时,重复值链中的记录总数,唯一值不计入 不能把它当作所有查询通用的重复行计数
INFO1 补充诊断信息 本例均为NULL;缺少版本定义时不解释为固定业务含义

本例哈希字段大多为0,动态哈希字段为NULL。结合聚合输入为0,不能认为这证明了有数据时哈希分布良好。

8.1 本例 ET 排名复核

RANK SEQ OP TIME(US) 占比 解释
1 1 NSET2 104 57.14% 结果收集节点的记账时间
2 8 SSCN 41 22.53% 驱动索引扫描
3 3 SORT3 11 6.04% 排序节点
4 0 DLCK 10 5.49% 额外内部操作符,未对应文本计划中的正序号节点
5 4 HAGR2 6 3.30% 哈希聚合
6 6 SLCT2 5 2.75% 类别过滤
7 2 PRJT2 2 1.10% 最终投影
7 7 IJI2 2 1.10% 索引嵌套循环连接
9 5 PRJT2 1 0.55% 聚合前投影

核算:

104 + 41 + 11 + 10 + 6 + 5 + 2 + 2 + 1 = 182 μs
104 / 182 × 100% ≈ 57.14%
41 / 182 × 100% ≈ 22.53%

百分比相加受四舍五入影响。这里的57.14%不是6.457毫秒的57.14%,也不是599.422毫秒的57.14%。

NSET2虽然排名第一,但绝对时间只有0.104毫秒,不足以认定它是需要优化的瓶颈。也不能因为它负责结果收集,就把这104微秒全部解释成网络传输。

DLCK的具体实现含义需要匹配版本与官方诊断资料;仅凭缩写不能断定发生死锁。它的10微秒也不能证明锁等待是本次主要问题。

8.2 为什么节点9~11未列在ET结果中

文本计划显示这三个节点都没有进入。ET本例只输出了9行,其中还有SEQ=0的额外内部项。合理解释是未执行分支没有形成相应的节点计时输出;不应把ET缺少节点直接理解成索引不存在或数据库丢失了执行步骤。

8.3 不能机械相加父子时间

本例可以求和来验证PERCENT分母,但这不意味着任何版本、并行环境或其他诊断工具的父子节点时间都能相加为完整耗时。必须先确定计时范围、是否含子节点、并行线程如何汇总。本文没有把ET之和当成完整SQL延迟。

9. 第五步:解释三个时间为何不一致

时间来源 本例 能支持的解释
ET节点时间之和 0.182 ms 本次列出的操作符记账总量
Statistics exec time 6.457 ms 执行统计的计时范围
末尾“已用时间” 599.422 ms 客户端对对应命令或输出过程显示的耗时,需确认命令归属

这三者可能涉及不同边界:解析与优化、执行初始化、节点执行、跟踪采集、客户端往返、取数和格式化显示等。但本记录不能量化各部分占比。

尤其末尾时间紧跟ET结果,且缺少此前命令历史,无法确认它属于原始业务查询、ET调用还是一次组合展示。因此不能把 599.422 - 6.457 全部归因于网络,也不能把 6.457 - 0.182 全部归因于解析。

若业务报告“接近600毫秒”,下一步应分别记录业务查询、ET调用、客户端请求开始与结束的时间,并核对三份信息是否属于同一次业务执行。ET调用本身的执行号也不能误当成被分析SQL的执行号。

10. 第六步:如何重新采集一份可比较的记录

下面是采集流程示意,不是已在目标数据库执行过的命令。语法、参数权限和工具行为以目标版本为准。

10.1 保存复现条件

记录数据库与客户端版本、原SQL、绑定值及类型、表和索引DDL、优化器统计信息时间、会话参数、事务状态、数据规模、并发情况,以及是否取完结果。涉及会话临时数据时,必须在能看到相同数据的会话中采集。

10.2 查看预估计划

EXPLAIN SELECT ...;

用它确认访问路径和估算行数,再与真实执行对比。不同绑定值、不同会话、数据变化或重优化都可能使重新生成的计划与先前实际执行不同。

10.3 检查监控参数并采集实际记录

SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME IN ('ENABLE_MONITOR', 'MONITOR_SQL_EXEC', 'ENABLE_MONITOR_DMSQL');

ET官方要求 ENABLE_MONITOR=1 与 MONITOR_SQL_EXEC=1。部分版本或工具的实际计划跟踪还涉及 ENABLE_MONITOR_DMSQL;应按目标版本核对,先记录原值,再按范围开启。会话级监控可参考以下形式:

CALL SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC', 1);

DIsql的实际跟踪示意:

SET AUTOTRACE TRACEONLY -- 在这里执行完整的目标查询,并完成取数 SET AUTOTRACE OFF

以上 SET 是客户端命令。实际跟踪会执行目标SQL,并非只打印预估方案。对于写操作,它会产生真实数据变更,不能把查询采集脚本直接套用为无副作用的写操作测试。

10.4 用目标执行号查看 ET

-- 123456仅示意,替换为刚才目标SQL的真实数值执行号 CALL ET(123456);

按SEQ将ET和实际计划对应;同时保存Statistics。采集后恢复原有参数值,避免把原本开启的共享监控一律关闭。

10.5 选择有代表性的样本

至少覆盖:空驱动集、正常业务数据量、较大的驱动集,以及不同选择性的绑定值。每种条件重复若干次,区分首次执行与后续执行,记录中位数及波动;不要为了测试随意清理生产缓存。

11. 第七步:按证据决定优化方向

11.1 优先确认空结果是否符合预期

当前最值得核查的是 TABLE_A 为什么输出0行。若业务本来就应该为空,这次执行路径可能完全正常;若业务预期有数据,则应先查数据准备、会话和条件。性能调优不能替代结果正确性验证。

11.2 有数据后,再评估右侧复合索引

当驱动集有数据时,观察右侧探测的累计输出、N_ENTER、逻辑读和回表开销。如果每个驱动键匹配很多候选,再被账簿、年度和期间过滤掉,才有依据评估复合索引是否需要让这些条件更早参与定位。

索引列顺序要同时考虑等值条件、范围条件、其他查询复用、列选择性和维护成本。没有DDL和非空执行样本时,不应直接给出“必建某个索引”的结论。

11.3 检查连接调用放大

嵌套循环适合外侧较小且内侧探测便宜的场景。有数据后应同时看外侧行数、内侧进入次数及累计时间。不能把进入次数直接视为匹配行数,但它能帮助发现重复探测放大。

若外侧规模很大且内侧累计代价高,再比较其他连接方案;当前空结果样本不支持强制改为哈希连接。

11.4 有明显估算偏差时,再核对优化器统计信息

1->0只说明这次估算与实际不一致,不能单次就判定统计信息失效。应跨典型绑定值观察数量级偏差,结合数据分布、列相关性、参数类型和统计信息新鲜度判断是否需要更新。

11.5 根据实际落盘和等待评估内存

SORT3耗时很小,磁盘使用和磁盘排序次数都为0,没有证据要求提高排序内存。只有在代表性样本中发现大量输入、明确落盘或相关等待,才进一步评估排序/哈希内存及并发总需求。

12. 常见误读速查

误读 正确判断
[2,1,450]表示实际执行2毫秒 第一项是优化器估算代价
N_ENTER=2表示两条结果 它是进入次数
没有箭头就是实际等于估算 未执行节点也可能只保留估算值
索引节点耗时0说明索引非常快 本例是节点未进入
SSCN一定比SSEK2差 要看访问范围、覆盖情况、数据量与累计成本
NSET2占比57%说明网络慢 ET不能单独完成这种归因
排序用了约18MiB就一定进行了大量排序 空输入也可能存在空间申请或记账
physical reads=0说明SQL没有开销 逻辑读、CPU、其他等待和客户端开销仍可能存在
ET结果“9 rows got”表示业务返回9行 它表示ET诊断结果有9条操作符记录
末尾599.422ms就是业务查询服务端时间 先核对它对应哪条命令及计时边界
此次很快说明大数据量也快 空驱动集未覆盖右侧真实工作量

13. 可复用的分析记录模板

【环境】数据库版本、客户端版本、会话参数、事务与并发:
【目标执行】SQL标识、执行号、绑定值与类型、取数是否完成:
【数据样本】驱动集规模、结果行数、首次或后续执行:
【计划】驱动表、扫描方式、索引、连接方式、聚合和排序:
【估算验证】关键节点预计行数→实际输出行数:
【未执行分支】N_ENTER=0的节点及其原因:
【Statistics】逻辑读、物理读、写入、排序、传输和exec time:
【ET】高耗时SEQ、绝对时间、占比、进入次数、空间及哈希情况:
【时间口径】节点时间、执行统计时间、客户端时间各自归属:
【结论】已证明的事实、尚需验证的推断:
【优化实验】一次改动、测试样本、结果正确性、资源与延迟对比:

参考资料

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服