作为刚接触sql优化的小白,需要尽快掌握的能力就是如何阅读执行计划树、核对实际行数、分析总体资源消耗,再用 ET 定位操作符开销。本文保留原始性能数字;数据库版本、原始 SQL、绑定值和表结构未提供,因此对内部标记和运行机制的解释会区分确定事实与待验证推断。
表统一表示为 TABLE_A、TABLE_B,索引统一表示为 IDX_A_01、IDX_B_01;业务表引用别名统一表示为 B,数据库生成的临时视图统一表示为 TEMP_VIEW_01。此外替换了业务标识常量和执行号。本文不附原名映射,避免文章重新暴露原始名称。列名、年度、期间边界和运行指标保留,以便解释条件与访问路径;这不是对所有业务信息的完全匿名化。
这份记录支持以下结论:
TABLE_A 一侧估算输出 1 行,实际输出 0 行。TABLE_B 的索引定位和回表节点进入次数为 0,未执行。| 信息 | 回答的问题 | 分析边界 |
|---|---|---|
| 执行计划 | 访问哪些对象,采用什么扫描、连接、聚合和排序方式 | 预估计划不能证明实际执行情况;本例附带实际行数和计时 |
| Statistics | 本次执行消耗了多少读、写、传输与时间资源 | 总体指标不能直接分摊到某个表或索引 |
| ET | 哪些操作符被调用,各自记录了多少时间、内存和磁盘空间 | 操作符计时不能直接代替完整请求耗时 |
普通 EXPLAIN 用于查看预估方案;实际跟踪还可以给出实际行数、进入次数和耗时。代价三元组的基础定义见官方《查询优化》。
################################################################################################################################################################################################
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 行。
计划树描述的是数据依赖。阅读时从下层数据来源向上理解,但执行器会由上层请求下层数据;嵌套循环还会反复进入右侧分支,不能把整棵树看成只运行一遍的固定行号顺序。
本例的设计路径可以简化为:
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 所需列是否由索引覆盖,应查看索引定义,不能仅凭其位于回表节点下方补写出索引列清单。
#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 为准。
NEST LOOP INDEX JOIN2 表示使用索引的嵌套循环连接;ET 中对应缩写 IJI2。通常左侧每提供一条记录,就用其中的键值探测右侧索引。
本例右侧 SSEK2 的范围由 TABLE_A.PK_ACCASOA 驱动,随后还有过滤和回表。可确定这些操作存在于计划中,但它们的 n_enter=0、耗时为 0,因此没有测到其真实开销。零耗时还要与进入次数一起看:单独的 0(ms) 也可能与计时精度有关。
B.VOUCHERKIND <> var8
var8 是计划显示的变量占位;不能仅凭名字确认它等于应用端第八个绑定参数,也不能恢复其值。分析时需核对实际值及数据类型,尤其要注意 NULL:SQL 中与 NULL 的普通不等比较不会得到 TRUE。
slct_pushdown(0) 表示该节点未采用对应的过滤下推优化标记,不能据此断言整条 SQL 所有条件都未下推,也不能直接推出“应强制下推”。
HAGR2 是哈希分组聚合。此处有两个分组项、18 个聚合函数项;分组列显示为优化器中间结果的 TEMP_VIEW_01.TMPCOL0 和 TMPCOL1。这些名字不能直接还原成原 SQL 的分组表达式。
本例输入为空且存在分组,实际没有分组输出。这与不带 GROUP BY 的单组 COUNT(*) 可能返回一条计数为 0 的记录不同。
计划存在 SORT3,内存记账 18416 KB,磁盘记账 0 KB,耗时 11 微秒。按 1024 换算,18416 KB 约为 17.98 MiB。
虽然实际没有输出行,排序结构仍可能在初始化阶段申请或登记空间;仅凭这里的字段,不能确定该值就是实际有效数据体积、进程常驻内存增量或可立刻回收的内存。Statistics 中内存排序次数为 0,也不与“计划存在排序节点”构成矛盾:计划结构、节点内存记账和实际排序次数是不同观测维度。
以下参数定义以官方《附录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 |
进入次数,不是实际输出行数,也不是物理读次数 |
本例范围为:
[(TABLE_A.PK_ACCASOA,min,min,min,min),
(TABLE_A.PK_ACCASOA,max,max,max,max))
直观含义是:按驱动记录给出的键值固定前导范围,后面的键分量取较宽边界。括号描述内部复合键边界,不宜直接改写为某个业务期间条件。
范围里没有直接出现账簿、年度和期间常量,而这些条件显示在 SLCT2 中。这提示我们:若有数据时右侧探测范围很大,应检查复合索引列顺序,以及这些过滤条件能否参与更精确的索引定位。还需核对隐藏定位键、索引定义和完整 SQL,不能单凭边界分量数断言“这是恰好五个业务列的索引”。
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节点时间分开 |
先看结果量:最终 0 行。再看读取:逻辑读 93,物理读及直接物理读为 0,本次统计不到磁盘读取压力。即使没有返回行,访问索引结构、元数据或执行初始化仍可能产生逻辑读;这里没有足够信息把93次全部归到节点8。
再看写入与排序:数据页、undo、redo和磁盘排序均为0,没有这些指标上的资源压力证据。最后看传输:空结果也存在协议和元数据传输,因此1671字节与返回0行并不矛盾。
不能仅由“物理读为0”推导出一个精确缓存命中率,也不能把93乘以某个未经核实的页大小当成唯一工作集大小。
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,不能认为这证明了有数据时哈希分布良好。
| 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微秒也不能证明锁等待是本次主要问题。
文本计划显示这三个节点都没有进入。ET本例只输出了9行,其中还有SEQ=0的额外内部项。合理解释是未执行分支没有形成相应的节点计时输出;不应把ET缺少节点直接理解成索引不存在或数据库丢失了执行步骤。
本例可以求和来验证PERCENT分母,但这不意味着任何版本、并行环境或其他诊断工具的父子节点时间都能相加为完整耗时。必须先确定计时范围、是否含子节点、并行线程如何汇总。本文没有把ET之和当成完整SQL延迟。
| 时间来源 | 本例 | 能支持的解释 |
|---|---|---|
| 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的执行号。
下面是采集流程示意,不是已在目标数据库执行过的命令。语法、参数权限和工具行为以目标版本为准。
记录数据库与客户端版本、原SQL、绑定值及类型、表和索引DDL、优化器统计信息时间、会话参数、事务状态、数据规模、并发情况,以及是否取完结果。涉及会话临时数据时,必须在能看到相同数据的会话中采集。
EXPLAIN
SELECT ...;
用它确认访问路径和估算行数,再与真实执行对比。不同绑定值、不同会话、数据变化或重优化都可能使重新生成的计划与先前实际执行不同。
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,并非只打印预估方案。对于写操作,它会产生真实数据变更,不能把查询采集脚本直接套用为无副作用的写操作测试。
-- 123456仅示意,替换为刚才目标SQL的真实数值执行号
CALL ET(123456);
按SEQ将ET和实际计划对应;同时保存Statistics。采集后恢复原有参数值,避免把原本开启的共享监控一律关闭。
至少覆盖:空驱动集、正常业务数据量、较大的驱动集,以及不同选择性的绑定值。每种条件重复若干次,区分首次执行与后续执行,记录中位数及波动;不要为了测试随意清理生产缓存。
当前最值得核查的是 TABLE_A 为什么输出0行。若业务本来就应该为空,这次执行路径可能完全正常;若业务预期有数据,则应先查数据准备、会话和条件。性能调优不能替代结果正确性验证。
当驱动集有数据时,观察右侧探测的累计输出、N_ENTER、逻辑读和回表开销。如果每个驱动键匹配很多候选,再被账簿、年度和期间过滤掉,才有依据评估复合索引是否需要让这些条件更早参与定位。
索引列顺序要同时考虑等值条件、范围条件、其他查询复用、列选择性和维护成本。没有DDL和非空执行样本时,不应直接给出“必建某个索引”的结论。
嵌套循环适合外侧较小且内侧探测便宜的场景。有数据后应同时看外侧行数、内侧进入次数及累计时间。不能把进入次数直接视为匹配行数,但它能帮助发现重复探测放大。
若外侧规模很大且内侧累计代价高,再比较其他连接方案;当前空结果样本不支持强制改为哈希连接。
1->0只说明这次估算与实际不一致,不能单次就判定统计信息失效。应跨典型绑定值观察数量级偏差,结合数据分布、列相关性、参数类型和统计信息新鲜度判断是否需要更新。
SORT3耗时很小,磁盘使用和磁盘排序次数都为0,没有证据要求提高排序内存。只有在代表性样本中发现大量输入、明确落盘或相关等待,才进一步评估排序/哈希内存及并发总需求。
| 误读 | 正确判断 |
|---|---|
[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就是业务查询服务端时间 | 先核对它对应哪条命令及计时边界 |
| 此次很快说明大数据量也快 | 空驱动集未覆盖右侧真实工作量 |
【环境】数据库版本、客户端版本、会话参数、事务与并发:
【目标执行】SQL标识、执行号、绑定值与类型、取数是否完成:
【数据样本】驱动集规模、结果行数、首次或后续执行:
【计划】驱动表、扫描方式、索引、连接方式、聚合和排序:
【估算验证】关键节点预计行数→实际输出行数:
【未执行分支】N_ENTER=0的节点及其原因:
【Statistics】逻辑读、物理读、写入、排序、传输和exec time:
【ET】高耗时SEQ、绝对时间、占比、进入次数、空间及哈希情况:
【时间口径】节点时间、执行统计时间、客户端时间各自归属:
【结论】已证明的事实、尚需验证的推断:
【优化实验】一次改动、测试样本、结果正确性、资源与延迟对比:
文章
阅读量
获赞
