Oracle执行计划是数据库优化器为SQL语句生成的执行路径描述,详细记录了数据读取、关联、过滤等操作的顺序和方式,是排查SQL性能问题的核心依据。通过对执行计划的深入分析,我们可以精准定位性能瓶颈,制定合理的优化策略。

一、获取Oracle执行计划
在Oracle中可以通过多种方式获取SQL语句的执行计划,最常用的是EXPLAIN_PLAN命令和DBMS_XPLAN包。
1.1 使用EXPLAIN_PLAN生成执行计划
该命令不会实际执行SQL,只会生成预测的执行计划并存入计划表,默认计划表为PLAN_TABLE。
-- 生成执行计划 EXPLAIN PLAN FOR SELECT e.empno, e.ename, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE e.sal > 5000; -- 查看执行计划 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
1.2 查看实际执行的执行计划
如果SQL已经执行过,可以通过DBMS_XPLAN.DISPLAY_CURSOR获取真实的执行计划,包含实际行数、执行时间等信息,比预测计划更准确。
-- 查看最近一次执行的SQL的执行计划,需要替换SQL_ID
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));二、执行计划核心字段解析
执行计划的输出包含多个关键字段,理解这些字段的含义是分析的基础。
| 字段名 | 含义说明 |
|---|---|
| Id | 执行步骤的编号,按照执行顺序排列 |
| Operation | 执行的操作类型,如TABLE ACCESS FULL(全表扫描)、INDEX RANGE SCAN(索引范围扫描) |
| Name | 操作对应的对象名称,如表名、索引名 |
| Rows | 优化器预估的该步骤返回的行数 |
| Bytes | 优化器预估的该步骤返回的数据量(字节) |
| Cost (%CPU) | 优化器估算的执行成本,括号内是CPU成本占比 |
| Time | 优化器预估的执行时间 |
三、常见性能问题识别与优化
3.1 全表扫描问题
当执行计划中Operation出现TABLE ACCESS FULL时,说明该表进行了全表扫描,通常在大表上出现时意味着性能问题。
优化方案:检查查询条件是否有合适的索引,若没有则创建对应索引;如果查询需要返回表中大部分数据,全表扫描可能是合理选择,无需优化。
-- 为emp表的sal字段创建索引,避免sal>5000时的全表扫描 CREATE INDEX idx_emp_sal ON emp(sal);
3.2 索引失效问题
即使表上有索引,以下情况可能导致索引无法使用:
- 对索引字段使用函数,如
WHERE UPPER(ename) = 'SMITH' - 索引字段参与运算,如
WHERE sal * 1.1 > 5000 - 使用不等于、
NOT IN、IS NULL等条件(部分版本优化器可能仍使用索引) - 隐式类型转换,如索引字段是VARCHAR2,查询时传入数字类型
优化方案:修改SQL写法,避免对索引字段做函数处理或运算;若必须做函数处理,可以创建函数索引。
-- 创建函数索引,支持UPPER(ename)的查询 CREATE INDEX idx_emp_ename_upper ON emp(UPPER(ename));
3.3 表关联顺序不合理
执行计划中表的关联顺序会影响性能,优化器通常会选择小表作为驱动表,但如果统计信息过时,可能选择错误的驱动表。
优化方案:更新表的统计信息,让优化器获取准确的表数据量信息:
-- 收集emp表的统计信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT', 'EMP');
-- 收集dept表的统计信息
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT', 'DEPT');四、执行计划分析注意事项
分析执行计划时需要注意以下几点:
- 预估的行数(Rows)和实际返回的行数差异过大时,说明统计信息可能过时,需要重新收集统计信息。
- Cost值只是优化器的估算值,实际执行效率还需要结合执行时间、逻辑读等指标判断。
- 不要盲目相信执行计划,需要结合实际业务场景和数据分布验证优化效果。
- 对于复杂的SQL,可以逐步拆解分析每个子查询的执行计划,定位具体的问题步骤。
执行计划分析是一个需要结合经验和实际场景的过程,多积累不同场景下的优化案例,能够快速提升问题排查效率。
五、完整分析示例
以下是一个慢查询的完整分析优化过程:
-- 原始慢查询SQL SELECT o.order_id, o.order_time, c.customer_name FROM orders o JOIN customers c ON o.customer_id = c.customer_id WHERE o.order_time >= DATE '2024-01-01' AND o.status = 'PAID' AND c.region = 'EAST'; -- 查看执行计划后发现orders表全表扫描,且orders表数据量超过1000万 -- 优化方案:创建复合索引 CREATE INDEX idx_orders_status_time ON orders(status, order_time, customer_id); -- 优化后再次查看执行计划,orders表变为索引范围扫描,执行时间从12秒降低到0.2秒
Oracle执行计划SQL性能优化EXPLAIN_PLAN修改时间:2026-06-06 23:39:08