先查DBA_HIST_SQLSTAT确认plan_hash_value是否真变:若7天内返回多行则确已漂移,仅一行则问题不在执行路径;再用DBMS_XPLAN.DISPLAY_AWR加+PEEKED_BINDS和+NOTE核对谓词、绑定值及SPM基线启用状态。

查 DBA_HIST_SQLSTAT 确认 plan_hash_value 是否真变了
执行计划“变差”不等于“变了”,AWR 是唯一能验证是否真实漂移的依据。只看 v$sql 或当前执行慢,容易误判为计划问题,实际可能是 I/O 抖动或锁争用。
运行这个查询(替换 your_sql_id):
SELECT plan_hash_value, COUNT(*), MIN(sample_time), MAX(sample_time) FROM dba_hist_sql_plan p JOIN dba_hist_sqlstat s USING (sql_id, plan_hash_value) WHERE sql_id = 'your_sql_id' AND sample_time > SYSDATE - 7 GROUP BY plan_hash_value ORDER BY MIN(sample_time);
- 返回多行 → 计划确实漂移过,继续往下查
- 只有一行 → 执行路径没变,问题大概率在统计信息、绑定变量窥探失效、内存压力或 RAC 节点间不一致
-
dba_hist_sql_plan默认每 SQL 最多存 1000 行计划(受_cursor_plan_cache_threshold控制),高频 SQL 可能被截断,结果为空 ≠ 没历史计划
用 DBMS_XPLAN.DISPLAY_AWR 对比两个 plan_hash_value 的实际路径
光有 hash 值不够,得确认访问方式是否退化:比如从 INDEX RANGE SCAN 变成 TABLE ACCESS FULL,或 NESTED LOOPS 变成 HASH JOIN 并 spill 到 TEMP。
执行时务必加 +PEEKED_BINDS 和 +NOTE:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR( sql_id => 'your_sql_id', plan_hash_value => 1234567890, db_id => 123456789, -- 从 dba_hist_sqlstat 查 format => 'BASIC +PEEKED_BINDS +NOTE' ));
- 不加
+PEEKED_BINDS→ 看不到绑定变量实际值,无法判断谓词是否被推入索引层 - 不加
+NOTE→ 无法确认 SPM 基线是否启用(如出现SQL plan baseline used) - 若提示 “no rows selected” → 不是计划不存在,而是该
plan_hash_value在 AWR 中未记录完整访问路径(常见于并行计划或递归调用)
交叉验证 disk_reads_delta 和 elapsed_time_delta 是否同步飙升
AWR 中 Physical Reads 暴增但 Elapsed Time 没涨,基本可断定是 I/O 路径恶化,而非 SQL 本身变慢;反之,若时间涨但物理读没涨,可能是 CPU 或锁问题。
- 查
disk_reads_delta突增时段(比如某小时从 500 涨到 12 万),记下sql_id和snap_id - 用同一
snap_id范围查dba_hist_sql_plan,确认该sql_id是否出现新plan_hash_value,且旧计划消失 - RAC 环境下必须分
instance_number查,否则dba_hist_seg_stat中的physical_writes是四节点叠加值,会掩盖真实热点
排除 SPM 基线未生效或绕过的干扰
很多人以为基线存在就等于生效,其实不然。DBA_SQL_PLAN_BASELINES 显示 ENABLED=YES 且 ACCEPTED=YES,只是“已入库”,不代表优化器真用了它。
- 用
DBMS_XPLAN.DISPLAY_AWR(..., 'ADVANCED')查输出中的 Note 行,明确是否有SQL plan baseline used - 若没这行,检查
optimizer_use_sql_plan_baselines是否为TRUE,以及该 SQL 是否被设为FIXED=YES后又未演进新计划 - RAC 下必须逐实例查
gv$sql,确保所有inst_id下都显示该 Note;单节点加载基线后,其他实例不会自动同步
真正难定位的是 plan_hash_value 相同但性能暴跌的情况——结构没变,但谓词没推入、绑定值导致基数误估、或 RAC 节点间 gc 等待激增,这些都不会改变 hash 值,却会让 AWR 的 Top 5 Timed Events 或 dba_hist_active_sess_history 暴露异常等待分布。


















