Oracle Jonathan Lewis 执行计划稳定性
Oracle Jonathan Lewis 执行计划稳定性
来源:Jonathan Lewis / jonathanlewis.wordpress.com 适用版本:Oracle Database 10g+ 文档版本:v1.0 / 2026-07-22
1. 概述
执行计划稳定性是 Jonathan Lewis 的重要话题[1]。
详细见:Oracle SQL Plan Baseline 详解。
2. 执行计划不稳定
2.1 原因
- 统计信息变化
- 数据分布变化
- 参数变化
- 绑定变量窥探
- 软件升级
2.2 影响
- 性能突变
- 业务影响
- 难诊断
2.3 Jonathan 观点
- 执行计划突变常见
- 需要稳定机制
- 监控
3. 稳定方法
3.1 Stored Outlines
- 8i+
- 旧机制
- 逐渐弃用
3.2 SQL Profile
- 10g+
- 自动调优
- 辅助信息
3.3 SQL Plan Baseline
- 11g+
- 推荐
- 防止回归
3.4 SQL Patch
- 11g+
- 注入 HINT
- 临时
3.5 Jonathan 推荐
- Baseline 优先
- Profile 次之
- Outlines 弃用
4. SQL Profile
4.1 创建
-- 自动
DECLARE
v_sql_id VARCHAR2(13) := '&sql_id';
BEGIN
DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(
task_name => 'task_' || v_sql_id,
name => 'profile_' || v_sql_id,
FORCE_MATCH => TRUE);
END;
/
4.2 查看
SELECT name, type, status, force_matching
FROM dba_sql_profiles;
4.3 删除
EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('profile_abc');
4.4 Jonathan 分析
- Profile 辅助 CBO
- 不强制
- 灵活
5. SQL Plan Baseline
5.1 捕获
ALTER SYSTEM SET optimizer_capture_sql_plan_baselines=TRUE;
5.2 使用
ALTER SYSTEM SET optimizer_use_sql_plan_baselines=TRUE;
5.3 查看
SELECT sql_handle, plan_name, enabled, accepted
FROM dba_sql_plan_baselines;
5.4 演化
-- 自动
SELECT * FROM dba_sql_plan_baselines WHERE accepted='NO';
-- 手动
DECLARE
v_report CLOB;
BEGIN
v_report := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
sql_handle => '&sql_handle');
DBMS_OUTPUT.PUT_LINE(v_report);
END;
/
5.5 固定
-- 固定计划
DECLARE
v_plans PLS_INTEGER;
BEGIN
v_plans := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(
sql_handle => '&sql_handle',
plan_name => '&plan_name',
attribute_name => 'fixed',
attribute_value => 'YES');
END;
/
5.6 Jonathan 建议
- 捕获历史
- 防止回归
- 演化新计划
6. SQL Patch
6.1 创建
DECLARE
v_patch_name VARCHAR2(30);
BEGIN
v_patch_name := DBMS_SQLDIAG.CREATE_SQL_PATCH(
sql_id => '&sql_id',
hint_text => 'INDEX(emp idx_emp)',
name => 'patch_abc');
END;
/
6.2 查看
SELECT name, status, force_matching
FROM dba_sql_patches;
6.3 删除
EXEC DBMS_SQLDIAG.DROP_SQL_PATCH('patch_abc');
6.4 Jonathan 用途
- 注入 HINT
- 临时
- 不改代码
7. 统计信息管理
7.1 锁定
-- 锁定表统计
EXEC DBMS_STATS.LOCK_TABLE_STATS('SCOTT','EMP');
-- 解锁
EXEC DBMS_STATS.UNLOCK_TABLE_STATS('SCOTT','EMP');
7.2 备份
-- 创建备份表
EXEC DBMS_STATS.CREATE_STAT_TABLE('SCOTT','STAT_BACKUP');
-- 导出
EXEC DBMS_STATS.EXPORT_TABLE_STATS('SCOTT','EMP','STAT_BACKUP');
7.3 恢复
EXEC DBMS_STATS.IMPORT_TABLE_STATS('SCOTT','EMP','STAT_BACKUP');
7.4 Jonathan 建议
- 关键表锁定
- 备份统计
- 可恢复
8. 监控
8.1 计划变化
SELECT sql_id, plan_hash_value, count(*)
FROM dba_hist_sqlstat
WHERE sql_id = '&sql_id'
GROUP BY sql_id, plan_hash_value;
8.2 Baseline 使用
SELECT sql_handle, plan_name, enabled, accepted, executions
FROM dba_sql_plan_baselines;
8.3 性能回归
SELECT snap_id, plan_hash_value, elapsed_time
FROM dba_hist_sqlstat
WHERE sql_id = '&sql_id'
ORDER BY snap_id;
9. 升级稳定
9.1 升级前
- 收集所有 SQL
- 导出执行计划
- Baseline
9.2 升级后
- 启用 Baseline
- 监控
- 演化
9.3 Jonathan 强调
- 升级风险高
- Baseline 保护
- 渐进
10. 案例:性能突变
10.1 现象
- SQL 性能突变
- 执行计划变化
10.2 Jonathan 诊断
1. 查看历史计划
2. 查看统计信息变化
3. 找出根因
4. Baseline 固定
10.3 修复
- 恢复旧统计
- 或 Baseline 固定
- 验证
11. Jonathan 方法论
11.1 预防
- Baseline 捕获
- 监控
- 文档
11.2 响应
- 查找根因
- 恢复
- 优化
11.3 改进
- 演化新计划
- 评估
- 接受
12. 常见问题
12.1 Baseline 不生效
- 参数
- enabled/accepted
- 检查
12.2 Profile 失效
- 统计信息变化大
- 重新调优
12.3 升级回归
- Baseline 保护
- 评估
- 演化
13. 最佳实践
- Baseline:捕获
- 统计信息:准确
- 监控:计划变化
- Profile:调优
- Patch:临时
- 锁定:关键表
- 备份:统计
- 演化:新计划
- 升级:保护
- 文档:记录
14. 参考资料
[1] Jonathan Lewis, https://jonathanlewis.wordpress.com [2] Oracle Database SQL Tuning Guide 19c, “SQL Plan Management”