执行计划频繁变化主因是SQL计划基线未生效或被绕过,需检查DBA_SQL_PLAN_BASELINES中ENABLED和ACCEPTED状态,并通过AWR验证基线是否真正启用。

执行计划频繁变化不是优化器“抽风”,而是基线没生效或被绕过
Oracle 19c 及以上版本中,执行计划跳变绝大多数情况下跟统计信息刷新、绑定变量值无关,真正卡在 DBA_SQL_PLAN_BASELINES 状态上:你看到的“已创建基线”,很可能 ENABLED=NO 或 ACCEPTED=NO。AWR 里 plan_hash_value 变来变去,不代表优化器在乱选,只说明 SPM 没真正介入决策。
- 查基线状态必须用:
SELECT sql_handle, plan_name, enabled, accepted, fixed FROM dba_sql_plan_baselines WHERE sql_text LIKE '%your_sql%' -
ENABLED=NO→ 基线存在但被禁用,optimizer_use_sql_plan_baselines=TRUE也白搭 -
ACCEPTED=NO→ 基线是自动捕获但未验证通过,不会被选用 - RAC 环境下要逐实例查
gv$sql,别只看单节点v$sql;一个实例显示Note: SQL plan baseline used,另一个没有,就是同步问题
AWR 是唯一能验证基线是否真起作用的工具
别只盯着 v$sql 里当前缓存的那条计划——它可能只是某次硬解析的临时产物。AWR 快照才是历史行为的客观记录,能交叉验证基线是否稳定生效。
- 先定位
sql_id:SELECT sql_id FROM dba_hist_sqltext WHERE sql_text LIKE '%关键条件%' - 再查该 SQL 在各快照中是否稳定:
SELECT snap_id, plan_hash_value, executions_delta FROM dba_hist_sqlstat WHERE sql_id = 'xxx' ORDER BY snap_id - 关键验证命令(必须加
'ADVANCED'):SELECT * FROM TABLE(dbms_xplan.display_awr('sql_id', NULL, NULL, 'ADVANCED')) - 重点看输出里的
Note行:只有出现SQL plan baseline SQL_PLAN_abc123 used for this statement才算真正启用
PLAN_HASH_VALUE 相同 ≠ 性能稳定
AWR 显示 plan_hash_value 一直没变,但响应时间忽高忽低?这不是基线失效,而是执行树结构一致,但底层行为已偏移。
- 查
dba_hist_active_sess_history对比两个快照的等待事件分布:SELECT event, COUNT(*) FROM dba_hist_active_sess_history WHERE sql_id = 'xxx' AND snap_id IN (12345, 12346) GROUP BY event - 典型异常信号:同一 SQL 在不同节点上,一个大量出现
gc cr block 2-way,另一个几乎没有 → RAC 数据块争用不均 -
plan_hash_value相同只代表操作符类型和连接顺序一样,不保证每个节点实际扫描行数、内存分配、并行度一致
动态SQL、SET选项、参数嗅探会直接绕过基线
哪怕你把基线设成 FIXED=YES,以下三类写法仍会让 SPM 彻底失效——因为 Oracle 根本不把它当“同一个 SQL”处理。
- 存储过程中用
EXEC(@sql)拼接字符串 → 每次生成新 SQL 文本,哈希值不同,基线不匹配 - 连接会话中
SET ARITHABORT ON和OFF并存 → SQL Server 同理,Oracle 中类似的是optimizer_mode或cursor_sharing会话级变更 - 绑定变量首次传入极偏值(如
:status = 'archived'占 0.01% 行),触发硬解析生成劣质计划并缓存 → 后续所有值都复用,基线根本没机会介入
基线不是保险丝,它只对“标准形态”的 SQL 生效;一旦语句文本、会话环境、参数值发生不可控偏移,SPM 就退场了——这点最容易被忽略。


















