达梦数据库的执行计划操作符介绍
🚨 最高频:数据访问类(看执行计划第一眼就看这里)
这是决定 SQL 快慢的根本。达梦默认建表是索引组织表,所以它的"全表扫描"操作符叫 CSCN2 而不是通常的 TABLE SCAN。
| 操作符 | 含义 | 你该关注什么 |
|---|---|---|
| CSCN2 | 聚集索引扫描(全表扫描) | 重点警惕。如果表数据量大、并发高,看到它基本意味着这条 SQL 有优化空间 |
| SSEK2 | 二级索引数据定位(范围扫描) | 看范围 。如果扫描范围是 [min, max](全范围),效果和全表扫差不多;如果是具体值(如 scan_range[10,10]),才是健康的 |
| BLKUP2 | 回表(二次扫描) | 看行数。通过二级索引拿到 rowid 后回表取完整数据。回表行数少还好,如果回表几千上万行,代价很高 |
| SSCN | 二级索引全扫描 | 索引全扫,不需要回表。常见于 SELECT 索引列 且索引覆盖的场景 |
| CSEK2 | 聚集索引数据定位 | 通过聚集索引键精准定位,不需要回表,效率高 |
一句话口诀:CSCN 要小心,SSEK 看范围,BLKUP 看行数。
🔗 高频:连接类
| 操作符 | 含义 | 适用场景 |
|---|---|---|
| HASH2 INNER JOIN | 哈希内连接 | 等值连接,无可用索引或优化器认为哈希更划算。注意内存消耗 |
| NEST LOOP INNER JOIN2 | 嵌套循环内连接 | 驱动表结果集小、被驱动表连接列有索引时效率高 |
| NEST LOOP INDEX JOIN2 | 索引内连接 | 被驱动表通过索引直接查找,比普通嵌套循环更优 |
| MERGE INNER JOIN3 | 归并内连接 | 两表连接列都有索引且有序,归并即可完成 |
| HASH LEFT JOIN2 | 哈希左外连接 | 左外连接的哈希实现 |
| HASH RIGHT JOIN2 | 哈希右外连接 | 右外连接的哈希实现 |
| HASH LEFT SEMI JOIN2 | 哈希左半连接 | 用于 IN / EXISTS 子查询,只返回左表匹配的行 |
| NEST LOOP LEFT JOIN2 | 嵌套循环左外连接 | 小表驱动左外连接 |
🧹 高频:处理与过滤类
| 操作符 | 含义 | 说明 |
|---|---|---|
| SLCT2 | 选择(过滤) | WHERE 条件过滤。如果扫描 10000 行只过滤出 1 行,考虑在过滤列加索引 |
| PRJT2 | 投影 | 选择表达式项的计算,广泛存在于每个计划中,正常操作 |
| SORT2 / SORT3 | 排序 | SORT3 多了 top_flag(取前 N 行)和 can_discard(管道模式)等标记 |
| TOPN2 | 取前 N 条 | LIMIT / ROWNUM 的实现。越早出现越好,理想情况是 TOPN2 在 BLKUP2 之前 |
| DISTINCT | 去重 | 对结果集去重 |
📊 高频:聚合类
| 操作符 | 含义 | 场景 |
|---|---|---|
| AAGR2 | 简单聚集 | 无 GROUP BY 的聚合,如 SELECT COUNT(*) |
| FAGR2 | 快速聚集 | 无过滤条件时,从索引直接取 MAX/MIN/COUNT,非常高效 |
| HAGR2 | HASH 分组聚集 | 分组列无索引时使用,需要建哈希表 |
| SAGR2 | 流分组聚集 | 输入流已按分组列有序,只需相邻比较,效率高 |
📦 高频:结果集与临时表
| 操作符 | 含义 | 说明 |
|---|---|---|
| NSET2 | 结果集收集 | 通常是计划顶层节点,返回最终结果 |
| HEAP TABLE | 临时结果表 | 存放中间结果,常见于复杂查询 |
| HEAP TABLE SCAN | 临时结果表扫描 | 读取上面那个临时表 |
📝 中低频:DML 操作(增删改)
| 操作符 | 含义 |
|---|---|
| INSERT / INSERT3 | 插入记录。INSERT3 是 MPP 模式下的查询插入优化 |
| UPDATE / DELETE | 更新/删除数据 |
| MERGE INTO | 合并数据(UPSERT) |
| INSERT_REMOTE / UPDATE_REMOTE / DELETE_REMOTE | DBLINK 远程操作 |
🌐 中低频:MPP / 并行 / DBLINK
| 操作符 | 含义 |
|---|---|
| ESEND / ERECV | MPP 环境下数据发送/接收 |
| MPP DISTRIBUTE / MPP GATHER / MPP BROADCAST | MPP 模式下的分发、收集、广播 |
| LSEND / LRECV | 本地并行查询下的发送/接收 |
| GI | Granule Iterator,控制并行扫描粒度 |
| BLKUP2 配合 ESEND | MPP 下回表数据发送 |
🗄️ 低频:HUGE 表专用
HUGE 表是达梦的列存储/水平分区表,有独立的操作符前缀 HF:
| 操作符 | 含义 |
|---|---|
| HFSCN / HFSCN2 | HUGE 表逐行扫描 |
| HFSEK / HFSEK2 | 根据 KEY 检索 HUGE 表 |
| HFI / HFI2 / HFINS2 / HFINS3 | HUGE 表插入 |
| HFLKUP / HFLKUP2 | 根据 ROWID 检索 HUGE 表 |
| HFD / HFDEL | HUGE 表删除 |
| HFU / HFS UPDATE | HUGE 表更新 |
⚠️ 低频:其他特殊操作符
| 操作符 | 含义 | 什么时候会看到 |
|---|---|---|
| ACTRL | 自适应计划控制 | 使用自适应计划机制时 |
| PIPE2 | 管道 | 左孩子触发右孩子执行,典型场景是 CONNECT BY 层次查询 |
| HIERARCHICAL QUERY | 层次查询 | CONNECT BY 语句 |
| MODEL | MODEL 子句 | 使用 Oracle 兼容的 MODEL 语法时 |
| CTE_SCN | 递归 WITH 查询 | WITH RECURSIVE |
| RN / RNSK | ROWNUM | ROWNUM 过滤条件 |
| ASSERT | 约束检查 | 约束验证 |
| STAT | 统计信息计算 | 收集统计信息时 |
| MVCC CHECK | 多版本检查 | MVCC 机制相关 |
| SET TRANSACTION / START TRANSACTION | 事务操作 | 事务控制 |
| LOCK TID | 上锁 | 锁定操作 |
| FILL BTR | 填充 B 树 | 索引维护 |
| CONST VALUE LIST | 常量列表 | 如 SELECT * FROM (VALUES (1),(2)) |
| ASCN / PSCN | 数组/参数当表扫描 | 特殊语法 |
| EXCEPT / EXCEPT ALL / INTERSECT / INTERSECT ALL / UNION / UNION ALL | 集合运算 | 集合操作 |
| UNION FOR OR2 / UNION FOR OR(MERGE) | OR 过滤的 UNION | 特定 OR 优化 |
| UNION ALL(MERGE) | 归并 UNION ALL | 有序归并优化 |
| SPL2 | 临时表(编号访问) | 物化后按 KEY 定位访问 |
| NTTS2 | 临时表(传递访问) | 数据主动传给父节点 |
| REMOTE SCAN | DBLINK 远程表扫描 | 跨库查询 |
| LSET | DBLINK 查询结果集 | DBLINK 结果收集 |
| CTNS | 全文索引 CONTAINS | 全文检索 |
| BM* 系列(BMAND/BMOR/BMSEK 等) | 位图索引运算 | 位图索引 |
| AFUN | 分析函数计算 | OVER() 窗口函数 |
| DSCN | 动态视图表扫描 | 动态性能视图 |
| NCUR2 | 游标操作 | 游标 |
| UFLT | UPDATE FROM 处理 | UPDATE 带 FROM 子句 |
| CONSTC / DSSEK / CONST VALUE LIST | 常量/跳跃扫描相关 | 特定索引优化 |
💡 怎么读执行计划
- 阅读顺序:从缩进最深的叶子节点开始,从下往上读("最右最上先执行")。
- 先看访问路径:CSCN2 还是 SSEK2?有没有 BLKUP2 回表?
- 再看过滤:SLCT2 过滤率高不高?
- 最后看连接和聚合:HASH 还是 NEST LOOP?聚合是 HAGR 还是 SAGR?
- 危险信号速查 :CSCN2(全表扫)、SSEK2 范围是
(min,max)(全索引扫)、BLKUP2 回表行数很大、TOPN2 出现太晚。