必须用gv$active_session_history配合动态时间窗口和plan_hash_value聚合来定位sql执行计划切换,因其能暴露ash中sql_plan_hash_value的时间突变,避免rac节点样本遗漏和时区导致的断点错位。

查 gv$active_session_history 时必须用动态时间窗口 + plan_hash_value 聚合
ASH 本身不记录计划变更事件,但能通过 sql_plan_hash_value 在时间轴上的突变暴露计划切换。直接查 v$active_session_history 会漏掉 RAC 其他节点的样本,必须用 gv$active_session_history;时间范围不能写死,否则跨时区或采样抖动会导致断点错位。
常见错误现象:在单实例上查到某 sql_id 的 plan_hash_value 在 14:02 出现新值,但在 RAC 环境中该计划其实在 node3 上 14:01:58 就已启用,你却只看到 coordinator 节点延迟上报的样本。
- 用
SAMPLE_TIME > SYSDATE - INTERVAL '30' MINUTE动态过滤,避免 NLS 或时区导致时间解析失败 - 按
TRUNC(sample_time, 'MI')分钟级分组,观察plan_hash_value是否在某分钟内集中切换(非渐进式) - 加
session_state = 'ON CPU'过滤,排除等待事件干扰,聚焦真实执行路径变化 - 若返回空,不是没切换,而是该 SQL 当前未活跃——切到
dba_hist_active_sess_history查历史
对比 DBA_HIST_SQL_PLAN 找出 plan_hash_value 首次出现时间
dba_hist_sql_plan 是定位“第一次用这个计划”的权威来源,但它不存采样时间戳,只存快照 ID 和生成时间。直接查 timestamp 字段不可靠,应以 dbid 和 instance_number 对齐 AWR 快照周期,再反推实际生效时刻。
容易踩的坑:同一 sql_id 在不同快照里可能有多个 plan_hash_value,但只有第一个被标记为 enabled 的才是真实切换点;accepted = 'YES' 不代表正在用,得结合 origin = 'AUTO-CAPTURED' 判断是否来自自适应计划捕获。
- 查语句必须带
WHERE dbid = (SELECT dbid FROM v$database)和instance_number = (SELECT instance_number FROM v$instance) - 用
MIN(snap_id)找出某plan_hash_value首次出现的快照,再查dba_hist_snapshot中该快照的begin_interval_time - 注意
dba_hist_sql_plan默认只保留最近 8 天数据,SELECT retention FROM dba_hist_wr_control先确认是否还存在
用 dbms_xplan.display_cursor 验证当前内存中计划是否已切换
dbms_xplan.display_cursor 显示的是共享池中当前游标的真实执行路径,但它不反映历史状态。如果刚发生计划切换,这里能看到新计划;但如果 SQL 已老化出共享池,它会返回空或旧计划——此时不能误判“没切”。
关键区别在于:ASH 显示“谁在跑”,display_cursor 显示“谁还在内存里”。两者不一致时,说明计划已切但老游标尚未失效,或新计划尚未被大量执行触发重载。
- 执行
SELECT * FROM TABLE(dbms_xplan.display_cursor('xxx', NULL, 'outline +peeked_binds')),重点看Plan hash value行是否与 ASH 中最新样本一致 - 若
peeked_binds显示绑定变量值明显偏离统计信息直方图分界点(如:b1 = 'Z'而直方图峰值在'A'),大概率触发了计划变更 - 别信
v$sql.plan_hash_value的平均值——同一sql_id下不同child_number可能对应完全不同的plan_hash_value
结合 AWR 报告中的 SQL Monitoring 找出切换前后性能断层
AWR 报告里的 “SQL Statistics” 按快照聚合,无法精确定位秒级切换点,但能发现执行耗时、逻辑读、CPU 时间的阶跃式变化。这种断层往往比 ASH 更早暴露问题——因为计划一变,指标立刻跳变,而 ASH 需要足够样本才能聚合成趋势。
典型信号:某 sql_id 在连续两个快照中,Elapsed Time per Exec (s) 从 0.2 跳到 42.7,且 Buffer Gets per Exec 同步暴涨 10 倍,基本可锁定为计划劣化而非数据倾斜。
- 打开 AWR 报告后,直接 Ctrl+F 搜该
sql_id,看 “SQL ordered by Elapsed Time” 表中相邻快照的数值差 - 对比 “SQL ordered by CPU Time” 和 “SQL ordered by Buffer Gets”,三者同步跳变才可信;若仅 CPU 上升而 Buffer Gets 不变,可能是硬解析风暴
- 报告底部 “Instance Activity Stats” 中
parse time elapsed若同步飙升,说明计划变更引发大量硬解析,需检查_optimizer_adaptive_plans是否开启
真实切换点往往卡在 ASH 样本密度突增、plan_hash_value 集中替换、AWR 指标断层这三者的交叠时间窗口里,而不是某条日志或某个快照的整点时刻。











