为什么需要查看执行计划?
因为只看SQL文本和总耗时,很难知道sql慢在哪里;执行计划则会详细描述数据库如何获得这些数据,包括扫描方式、索引选择、表连接方式以及排序、聚合等处理步骤。
执行计划用于解释性能现象,但不能独立解释所有慢 SQL。锁等待、并发负载、存储响应和客户端取数也可能影响耗时,需要结合监控分析。优化器的选择依赖统计信息等输入,因此“有索引”并不代表一定应当使用索引。参见官方《查询优化》。
| 信息类型 | 回答的问题 | 典型获取方式 | 主要局限 |
|---|---|---|---|
| 预估执行计划 | 当前环境下,优化器准备怎样执行? | EXPLAIN、EXPLAIN FOR、图形界面的执行计划入口 | 无法证明实际耗时与实际行数 |
| 实际执行计划及运行统计 | 某一次执行采用了什么计划、消耗了哪些资源? | AUTOTRACE TRACE/TRACEONLY、SQL Monitor、ET | 需要执行和采集,存在额外开销 |
| 缓存中的计划 | 服务器当前保留了哪些计划? | VSQL_PLAN、VCACHEPLN 等 | 缓存可能淘汰,也不等于某次执行的完整统计 |
“实际采用的计划”不表示计划中的每个字段都是实测值;其中的 COST 等字段仍可能是优化器估算。是否提供实际行数及具体统计项,应以版本和输出为准。
| 方案 | 获取步骤 | 是否执行目标 SQL | 适用场景 |
|---|---|---|---|
| EXPLAIN | 在目标 SQL 前加 EXPLAIN → 提交 → 查看文本计划树 | 否 | 快速检查扫描、索引及连接方式 |
| EXPLAIN FOR | 在目标 SQL 前加 EXPLAIN FOR → 提交 → 保存结构化结果 | 否 | 比较计划字段、整理分析报告 |
| SET AUTOTRACE | 选择模式 → 提交目标 SQL → 查看计划和统计 → 关闭跟踪 | 取决于模式 | 命令行复现与整体资源分析 |
| SQL Monitor | 开启监控 → 执行 SQL → 取得执行号 → 调用报告函数 | 采集需要执行;读取报告无需重跑 | 分析某次执行的详细情况 |
| ET | 开启操作符监控 → 执行 SQL → 取得执行号 → CALL ET | 采集需要执行;读取结果无需重跑 | 定位耗时操作符 |
| 图形化工具 | 连接数据库 → 选中 SQL → 点击执行计划;实际统计另走监控入口 | 取决于入口 | 日常开发、直观阅读 |
| 缓存计划与动态视图 | 定位 SQL → 查询缓存或节点视图 → 必要时导出 | 读取现有信息无需重跑 | 排查应用与手工测试计划不一致 |
下文统一使用业务表示例 APP.EMPLOYEE,假定存在 EMPLOYEE_ID、EMPLOYEE_NAME、DEPARTMENT_ID 三个字段。运行时请替换为实际对象。
执行命令:
EXPLAIN
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
查看计划中的扫描节点、索引名称、过滤条件和连接方式。它适合回答“当前优化器是否选择了预期访问路径”。
优点:
缺点:
**适用场景:**优化前的初步检查,以及改写或索引调整后的计划验证。
官方语法及权限要求参见《数据查询语句》4.19。
执行命令:
EXPLAIN FOR
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
-- 也可以为计划命名
EXPLAIN AS EMP_DEPT_PLAN FOR
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
它将计划作为结果集返回,便于导出。重点字段包括 OPERATION、TAB_NAME、IDX_NAME、ROW_NUMS、COST、FILTER 和 JOIN_COND,还可包含分区范围及优化建议。
优点:
缺点:
**适用场景:**计划对比、分析记录和结构化导出。
语法和结果说明参见官方《数据查询语句》EXPLAIN FOR。
这是 DIsql 客户端命令,应在 DIsql 中使用,不能默认作为普通 SQL 发送给任意 JDBC 工具。
模式区别:
| 模式 | 是否执行目标 SQL | 输出特点 |
|---|---|---|
| OFF | 正常执行 | 关闭自动跟踪 |
| NL | 否 | 显示嵌套循环相关操作符 |
| INDEX / ON | 否 | 显示扫描方式、表名及索引 |
| TRACE | 是 | 查询结果、实际计划和部分执行统计 |
| TRACEONLY | 是 | 实际计划和部分执行统计,不打印查询结果集 |
执行命令:
-- 前提:ENABLE_MONITOR、ENABLE_MONITOR_DMSQL 已按当前版本要求开启。
-- 记录 MONITOR_SQL_EXEC 原值后,在本会话开启操作符监控。
SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC', 1);
SET AUTOTRACE TRACEONLY
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
SET AUTOTRACE OFF
-- 分析完成后,将本次修改的监控参数恢复为原值。
**优点:**适合脚本复现,可同时观察实际计划、逻辑读、物理读及排序等统计。
**缺点:**TRACE 类模式需要真实执行,详细监控增加开销;TRACE 输出大量结果时还会增加客户端显示负担。
**注意:**达梦的 ON 不等同于其他数据库的同名模式;TRACEONLY 仍会执行 DML。它不打印查询结果,也不能据此认为执行过程完全没有网络开销。
模式和监控前提参见官方《DIsql 环境变量设置》3.3.19。
本文的 SQL Monitor 指达梦 DBMS_SQLTUNE.REPORT_SQL_MONITOR。不要直接套用其他数据库的监控命令、Hint 或报告选项。
执行步骤与命令:
-- 前提:ENABLE_MONITOR = 1,且当前版本支持该系统包。
SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC', 1);
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
-- 记录上面语句返回的执行号;以下 12345 仅为示例。
-- 在 DIsql 中增大 CLOB 显示长度,避免报告被截断。
SET LONG 1000000
SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(
SQL_EXEC_ID => 12345
)
FROM DUAL;
**优点:**以报告形式集中呈现一次执行的信息,适合检查计划节点、耗时和资源消耗,也便于留档。
**缺点:**依赖版本、系统包和监控数据;未提前采集或数据已淘汰时,不能保证事后补回。报告较长,需要正确处理 CLOB 输出。
**适用场景:**复杂 SQL 的深入分析和一次执行的性能取证。MPP 环境需在执行 SQL 的当前节点查询报告。报告参数和返回类型参见官方《DBMS_SQLTUNE 包》。
执行步骤与命令:
-- 前提:ENABLE_MONITOR = 1。
SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC', 1);
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM APP.EMPLOYEE
WHERE DEPARTMENT_ID = 10;
-- 使用目标语句的执行号替换示例值。
CALL ET(12345);
重点关注 OP(操作符)、TIME(微秒)、PERCENT(耗时占比)、RANK(耗时排名)、SEQ(计划节点号)和 N_ENTER(进入次数)。先找高耗时节点,再判断是否存在反复调用或数据处理过多。
**优点:**按执行号定位,能够把分析范围缩小到具体操作符;适合解释复杂计划的主要时间消耗。
**缺点:**需要提前启用监控;只有文本和执行号、没有保留的监控数据时,未必能查询成功。它用于节点开销分析,不能代替锁等待等系统诊断。
**适用场景:**已经确认 SQL 较慢,需要定位扫描、连接或排序等节点的实际开销。各版本开启条件可能不同,不应假设监控默认开启。参见官方《性能优化》4.2.3—4.2.4。
操作步骤:
DEM 的 SQL 开发模块也提供“执行计划”和“自动跟踪”等入口。其中“执行计划”相当于 EXPLAIN + SQL,不能因为采用图形显示就把它理解为实际执行统计。参见官方《DEM 使用手册》SQL 查询。
**优点:**计划树直观,适合交互分析和交流讲解。
**缺点:**不同工具和版本入口存在差异;截图不利于批量比较,建议同时保存 SQL 和文本计划。
**适用场景:**开发人员日常排查,以及需要直观展示计划结构的场景。
手工 EXPLAIN 与应用表现不一致时,可以检查服务器缓存和已有监控记录。
执行命令:
-- 先确认当前版本字段。
DESC V$CACHEPLN
DESC V$SQL_PLAN
SELECT CACHE_ITEM, SQLSTR
FROM V$CACHEPLN
WHERE SQLSTR LIKE '%APP.EMPLOYEE%';
SELECT *
FROM V$SQL_PLAN
WHERE SQLSTR LIKE '%APP.EMPLOYEE%';
进一步定位一次执行时,可以查询 V$SQL_HISTORY 的 EXEC_ID,再读取已采集的节点信息或监控报告。SQL_ID、EXEC_ID、CACHE_ITEM 含义不同,不能互相替换。
**优点:**读取已有信息时无需重跑目标 SQL,适合观察应用环境;能够辅助排查缓存重用问题。
**缺点:**计划和监控数据可能淘汰;模糊匹配可能命中其他语句,需要核对全文、用户和执行上下文。缓存视图也不是永久历史仓库,不能仅凭存在一份缓存计划就断定某次执行使用了它。
V$CACHEPLN 依赖 USE_PLN_POOL != 0;执行节点监控另有 ENABLE_MONITOR、MONITOR_SQL_EXEC 等要求。视图定义和条件参见官方《系统管理员手册·附录 2》。
某些排障流程还会将缓存计划转储到服务器文件。此类操作涉及构建版本、事件语法、文件路径及权限,入门分析优先使用上述查询和报告入口,确需转储时按对应版本手册执行。
| 常见操作符 | 基本含义 | 初步检查方向 |
|---|---|---|
| CSCN2 | 聚集索引全扫描,常表现为全表扫描 | 是否需要处理大量记录 |
| CSEK2 | 聚集索引范围扫描 | 扫描范围是否合理 |
| SSEK2 | 二级索引范围扫描 | 使用的索引及范围是否符合条件 |
| SSCN2 | 二级索引全扫描 | 是否仍扫描了大量索引记录 |
| BLKUP2 | 根据二级索引定位信息回表 | 回表次数和数据量是否过大 |
| NEST LOOP、HASH JOIN 等 | 表连接操作 | 数据规模、连接条件及重复调用 |
| SORT、聚合类操作符 | 排序或汇总处理 | 输入行数及实际资源消耗 |
操作符名称和后缀可能随版本变化。阅读时沿子节点到父节点理解数据流;多分支、并行和流水线执行不能仅靠文本上下顺序判断。具体解释参见官方《查询优化》。
建议每次至少保留:SQL 原文、绑定参数、环境版本、预估计划、实际执行号、实际统计、修改内容和对比结果。这样才能说明优化改变了什么,以及为什么有效。
文章
阅读量
获赞
