SQL 性能问题的核心通常集中在 执行计划(Execution Plan)。执行计划是优化器为某条 SQL 生成的“执行路线图”,决定了数据访问方式、连接顺序、聚合与排序策略等。理解并能读懂执行计划,是每个开发者与 DBA 进行 SQL 优化的基础技能。
学习目标:能用通过查看执行计划快速判断 SQL 是否走索引,能用 ET 获取真实执行统计,从而定位性能瓶颈。
执行计划是数据库优化器基于 SQL 语句、表结构、索引与统计信息,进行成本估算后选择的一组执行步骤。它将 SQL 的执行过程拆成多个节点(操作符),每个节点表示一次表扫描、索引扫描、连接、聚合、排序或投影等操作。
执行计划和实际执行统计:
为了演示,我们新建一个员工信息表。
SET SCHEMA TEST;
DROP TABLE IF EXISTS employees;
-- 员工信息表(employees)
CREATE TABLE employees (
id BIGINT PRIMARY KEY, -- 主键,演示时可手工赋值或用自增/sequence
emp_no VARCHAR(20) NOT NULL, -- 员工工号(业务唯一键)
name VARCHAR(100) NOT NULL, -- 员工姓名
dept_no INT, -- 部门编号
manager_id BIGINT, -- 直属领导(引用 employees.id,可为 NULL)
hire_date DATE, -- 入职日期
salary DECIMAL(12,2), -- 薪资
email VARCHAR(200), -- 邮箱(建议唯一)
phone VARCHAR(50), -- 电话
status VARCHAR(20) DEFAULT 'ACTIVE' -- 状态(ACTIVE/INACTIVE 等)
);
-- 按部门查询常用索引
CREATE INDEX idx_emp_dept ON employees(dept_no);
-- manager_id 用于自连接/查领导
CREATE INDEX idx_emp_manager ON employees(manager_id);
-- email 设唯一索引(如果业务允许)
CREATE UNIQUE INDEX ux_emp_email ON employees(email);
-- 组合索引示例(覆盖某些按部门和薪资筛选并排序的查询)
CREATE INDEX idx_dept_salary ON employees(dept_no, salary);
使用sqlark插入百万级数据
在命令行或客户端中使用 EXPLAIN
:
EXPLAIN SELECT * FROM EMPLOYEES WHERE DEPT_NO = 10;
1 #NSET2: [3, 2450, 315]
2 #PRJT2: [3, 2450, 315]; exp_num(11), is_atom(FALSE)
3 #BLKUP2: [3, 2450, 315]; IDX_EMP_DEPT(EMPLOYEES)
4 #SSEK2: [3, 2450, 315]; scan_type(ASC), IDX_EMP_DEPT(EMPLOYEES), scan_range[10,10], is_global(0)
该命令不会运行查询,只返回优化器选定的计划树(节点、估算行数、代价等)。适合开发时快速检查。对于执行计划的顺序,我们需要从里往外阅读:
SSEK2:在部门索引 IDX_EMP_DEPT
上查到 dept_no = 10
,优化器估计会匹配 2450 条。
BLKUP2:用这些索引记录去表里取完整行(也就是回表),预计需要做 2450 次表访问。
PRJT2:从取回的行里挑出要返回的列或进行必要的计算。
NSET2:把结果收集并返回给客户端(共 2450 行)。
达梦自带的图形化管理工具支持一件查看执行计划,以树状图或表格形式展示计划节点、索引与估算信息。图形化界面更直观,适合入门学习。
表格显示
图形显示
文本显示
disql下执行set autotrace trace
开启AUTOTRACE功能,执行SQL语句,并打印实际的执行计划。
sf_set_session_para_value('MONITOR_SQL_EXEC',1); --开启sql监控参数
set autotrace trace;
SELECT * FROM EMPLOYEES WHERE DEPT_NO = 10;
v$cachepln中保存了SQL缓冲区中的执行计划信息,这些则是我们真实的执行计划。在ini参数USE_PLN_POOL !=0时才统计。
USE_PLN_POOL = 1 #Query Plan Reuse Mode, 0: Forbidden; 1:strictly reuse, 2:parsing reuse, 3:mixed parsing reuse
根据v$cachepln中的cache_item可以获取实际执行计划信息
--先确认sql对应的执行计划缓存号cache_item
select cache_item, sqlstr from v$cachepln where SQLSTR like '%SELECT * FROM EMPLOYEES WHERE DEPT_NO = 10;%';
-- 执行以下命令,打印出缓存计划到默认路径,默认路径在数据库实例目录的trace文件夹中
Alter session set events 'immediate trace name plndump,level 140334006185072';
#切换至trace文件夹,将缓存计划文件cat出来
cd /home/dmdba/dmdbms/data/DAMENG/trace
cat [文件名]
EXPLAIN 或 GUI 输出通常包含以下关键字段:
TABLE SCAN
、INDEX SCAN
、NESTED LOOP
、HASH JOIN
等。以下为常见操作符与简要含义:
CSCN2
:聚集索引扫描或按聚集顺序扫描(类似全表扫描/聚集索引顺序扫描)。SSEK2
:二级索引扫描(先扫描索引,再回表定位数据)。BLKUP2
:回表 / 通过索引值访问表记录(会产生随机 IO)。PRJT2
:投影操作(计算或返回 select 列)。NSET2
:结果集收集(如合并、去重、临时结果缓存)。HASH JOIN
:哈希连接,适合大表的等值连接。NESTED LOOP
:嵌套循环连接,适合小表驱动或有高选择性索引的场景。参考阅读:附录 4 执行计划操作符| 达梦技术文档
逐步拆解一个较复杂的执行计划:
SELECT
的投影/聚合,判断是否有不必要的列或聚合。NESTED LOOP
还是 HASH JOIN
,并判断连接驱动表是否合理。ET 是在 SQL 真正执行时记录实际耗时、各节点实际返回行数与各操作耗时的跟踪工具。它能直接揭示优化器估算与真实执行的差距,是定位瓶颈的利器。
达梦ET有一定的开销,默认不启用,我们可以通过设置启动以下三个参数来启用ET:
ENABLE_MONITOR
MONITOR_TIME
MONITOR_SQL_EXEC
其中,ENABLE_MONITOR和MONITOR_TIME默认已开启,如果未开启可以使用如下方法开启
SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1); SP_SET_PARA_VALUE(1,'MONITOR_TIME',1);
MONITOR_SQL_EXEC是会话级动态参数,可以设置只针对当前会话开启
SF_SET_SESSION_PARA_VALUE('MONITOR_SQL_EXEC',1);
执行SQL语句,我们会看到一个执行号,直接点这个执行号,即可调用ET
在知道执行号的情况下,也可以这样使用ET
CALL ET(843);
注意 ⚠
在生产环境全面开启详细跟踪会带来较大开销,建议只对有问题的 SQL 或少数会话启用。
OP: 操作符
TIME(us): 时间开销,单位为微秒
PERCENT: 执行时间占总时间百分比
RANK: 执行时间耗时排序
SEQ: 执行计划节点号
N_ENTER: 进入次数
通过上述的方法,我们可以查看一条sql语句的执行过程,并根据相关指标初步推断出性能瓶颈,进而启发sql优化的相关思路。
文章
阅读量
获赞