注册
达梦数据库SQL执行计划的执行流程与具体含义
技术分享/ 文章详情 /

达梦数据库SQL执行计划的执行流程与具体含义

何处惹尘埃 2026/07/31 274 0 0

问题12:如何查看 SQL 的执行计划?各个操作符含义?结合例子说明 SQL 执行的流程

一、什么是执行计划

如果把数据库查询比作一次导航,SQL 语句是“目的地”,执行计划就是数据库“导航系统”规划的详细路线。同一条 SQL 可能有多种执行方式,数据库的优化器会基于统计信息选择它认为成本最低的路线。EXPLAIN 命令的作用,就是将这条路线以可读的格式呈现出来,帮助开发者理解数据库是如何执行 SQL 的。

二、查看执行计划的方法

在达梦中,使用 EXPLAIN 命令查看 SQL 语句的执行计划,该命令不会实际执行 SQL,仅输出优化器估算的执行步骤与代价。

EXPLAIN <SQL语句>;

执行计划以树形结构呈现,阅读顺序为 从内到外(最缩进的操作符最先执行)。

三、本次实操使用的表结构

  • TEST.EMPLOYEE:约 100004 行数据
  • TEST.DEPT:10 行数据

四、实操示例

4.1 等值条件查询(索引范围扫描)

SQL 语句

EXPLAIN SELECT ID, NAME FROM TEST.EMPLOYEE WHERE ID < 100;

执行计划输出

1   #NSET2: [1, 91, 64] 
2     #PRJT2: [1, 91, 64]; exp_num(3), is_atom(FALSE); INFO_BITS(0); BATCH_EXP_NUM(0); spl_info(NULL)
3       #BLKUP2: [1, 91, 64]; INDEX33555477(EMPLOYEE); use_clu_addr(0)
4         #SSEK2: [1, 91, 64]; scan_type(ASC), INDEX33555477(EMPLOYEE), scan_range(null2,100), is_global(0)

逐层解读

层级 操作符 说明
4(最内层) #SSEK2 ID 列的索引进行范围扫描,定位 ID &lt; 100 的记录位置
3 #BLKUP2 根据索引返回的 ROWID 回表读取完整行数据,获取 NAME
2 #PRJT2 投影操作,仅保留 IDNAME 两列
1 #NSET2 结果集,返回最终数据

代价信息解析[1, 91, 64] 分别表示:估算代价为 1、估算返回 91 行、估算数据量 64 字节。

4.2 前缀匹配查询(索引范围扫描)

首先为 NAME 列创建索引:

CREATE INDEX IDX_EMP_NAME ON TEST.EMPLOYEE(NAME);

SQL 语句

EXPLAIN SELECT ID, NAME FROM TEST.EMPLOYEE WHERE NAME LIKE '张%';

执行计划输出

1   #NSET2: [1, 1, 64] 
2     #PRJT2: [1, 1, 64]; exp_num(3), is_atom(FALSE); INFO_BITS(0); BATCH_EXP_NUM(0); spl_info(NULL)
3       #BLKUP2: [1, 1, 64]; IDX_EMP_NAME(EMPLOYEE); use_clu_addr(0)
4         #SSEK2: [1, 1, 64]; scan_type(ASC), IDX_EMP_NAME(EMPLOYEE), scan_range['张','掌'), is_global(0)

关键差异

  • scan_range['张','掌'):将 LIKE '张%' 转换为索引范围扫描(从 ‘张’ 到 ‘掌’ 的前开区间),这是达梦对字符串前缀匹配的优化实现方式。
  • 估算返回 1 行,代价极低。

4.3 两表连接查询(哈希连接)

SQL 语句

EXPLAIN SELECT E.NAME, D.DEPT_NAME FROM TEST.EMPLOYEE E JOIN TEST.DEPT D ON E.DEPT = D.DEPT_ID;

执行计划输出

1   #NSET2: [20, 333346, 148] 
2     #PRJT2: [20, 333346, 148]; exp_num(2), is_atom(FALSE); INFO_BITS(0); BATCH_EXP_NUM(0); spl_info(NULL)
3       #HASH2 INNER JOIN: [20, 333346, 148];  KEY_NUM(1); KEY(D.DEPT_ID=exp_cast(E.DEPT)) KEY_NULL_EQU(0)
4         #CSCN2: [1, 10, 52]; INDEX33555485(DEPT as D); btr_scan(1); need_slct(0); prejudge_iescn(0)
5         #CSCN2: [12, 100004, 96]; INDEX33555476(EMPLOYEE as E); btr_scan(1); need_slct(0); prejudge_iescn(0)

Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(D.DEPT_ID = exp_cast(E.DEPT))

逐层解读

层级 操作符 说明
5 #CSCN2 全表扫描 TEST.EMPLOYEE(驱动表)
4 #CSCN2 全表扫描 TEST.DEPT(被驱动表)
3 #HASH2 INNER JOIN 哈希内连接,连接条件为 D.DEPT_ID = exp_cast(E.DEPT)
2 #PRJT2 投影,选择 E.NAMED.DEPT_NAME
1 #NSET2 结果集

Predicate Informationaccess(D.DEPT_ID = exp_cast(E.DEPT)) 显示连接条件,其中 exp_cast 表示 E.DEPT 发生了隐式数据类型转换,建议保持连接列的数据类型一致以避免影响索引使用。

4.4 分组聚合查询(哈希分组)

SQL 语句

EXPLAIN SELECT DEPT, COUNT(*) FROM TEST.EMPLOYEE GROUP BY DEPT;

执行计划输出

1   #NSET2: [18, 2, 48] 
2     #PRJT2: [18, 2, 48]; exp_num(2), is_atom(FALSE); INFO_BITS(0); BATCH_EXP_NUM(0); spl_info(NULL)
3       #HAGR2: [18, 2, 48]; grp_num(1), sfun_num(1), distinct_flag[0]; slave_empty(0) keys(EMPLOYEE.DEPT) ; opt_info_bits(0)
4         #CSCN2: [11, 100004, 48]; INDEX33555476(EMPLOYEE); btr_scan(1); need_slct(0); prejudge_iescn(0)

逐层解读

层级 操作符 说明
4 #CSCN2 全表扫描 TEST.EMPLOYEE,读取所有行
3 #HAGR2 哈希分组聚合,对 DEPT 列分组并计算 COUNT(*)grp_num(1) 表示 1 个分组键,sfun_num(1) 表示 1 个聚合函数
2 #PRJT2 投影
1 #NSET2 结果集,估算返回 2 行(表示 DEPT 只有 2 个不同值)

五、常见操作符含义速查

操作符 说明
NSET2 结果集,执行计划最外层节点
PRJT2 投影操作,从结果中筛选指定列
SLCT2 过滤操作,对应 WHERE 条件
CSCN2 聚集索引全扫描(全表扫描)
SSCN 二级索引全扫描
SSEK2 二级索引范围扫描(精确定位)
BLKUP2 根据二级索引的 ROWID 回表取完整行数据
HASH2 INNER JOIN 哈希内连接,适用于大表等值连接
NEST LOOP JOIN2 嵌套循环连接,适用于小表驱动大表
AAGR2 简单聚集(无 GROUP BY 时的集函数计算)
HAGR2 哈希分组聚集(包含 GROUP BY)
SORT 排序操作,对应 ORDER BY
exp_cast 隐式数据类型转换

六、执行计划阅读要点

  1. 阅读顺序:从最内层(最缩进)开始,逐层向外执行。
  2. 代价信息:每个操作符后的 [代价, 估算行数, 估算字节数],代价越小表示执行成本越低。
  3. Predicate Information:显示连接条件和过滤条件的具体信息,可从中发现隐式类型转换等问题。
  4. 优化方向
    • CSCN2 出现于大表时,考虑添加索引。
    • exp_cast 出现时,检查连接列的数据类型是否一致。
    • 连接估算行数异常时,考虑更新统计信息。

七、实操验证结果汇总

SQL 类型 操作符链 关键特征
等值条件查询(ID < 100) SSEK2 → BLKUP2 → PRJT2 → NSET2 索引范围扫描 + 回表,估算 91 行
前缀匹配查询(LIKE ‘张%’) SSEK2 → BLKUP2 → PRJT2 → NSET2 索引范围扫描,scan_range['张','掌')
两表连接(JOIN) CSCN2 → CSCN2 → HASH2 INNER JOIN → PRJT2 → NSET2 全表扫描 + 哈希连接,存在隐式类型转换
分组聚合(GROUP BY) CSCN2 → HAGR2 → PRJT2 → NSET2 全表扫描 + 哈希分组,估算 2 个分组

通过 EXPLAIN 输出的执行计划,可以准确判断 SQL 的执行路径,从而识别性能瓶颈并进行针对性优化。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服