spm在rac中比stored outline更可靠,因其基于sql_id+plan_hash_value全局匹配,所有节点强制使用同一accepted计划,不受cursor_sharing、绑定变量窥探或统计信息同步延迟影响;而outline依赖会话级hint,易因子游标不一致或实例间配置差异失效。
oracle 19c rac 中 sql 解析性能问题,80% 不是硬解析开销本身,而是执行计划跳变引发的连锁反应:新计划可能触发大量物理读、并行倾斜、或错误选择 nl join 导致单节点 cpu 暴涨。spm 不是用来“加速解析”,而是用确定性压制不确定性——只要 accepted 为 yes 的基线存在,优化器就不会选未经验证的新计划。
为什么在 RAC 环境下 SPM 比 Stored Outline 更可靠
RAC 多实例共享同一套 SQL Management Base,但每个节点独立缓存游标和执行计划。Stored Outline 依赖于会话级 hint 绑定,容易因 cursor_sharing 设置、绑定变量窥探差异或实例间统计信息同步延迟而失效;SPM 则基于 SQL_ID + PLAN_HASH_VALUE 全局匹配,基线一旦接受,所有节点强制使用同一组 ACCEPTED 计划,不受 optimizer_mode 或 _optim_peek_user_binds 波动影响。
- Outline 在跨实例软解析时可能因子游标不一致被忽略,SPM 的 plan baseline 由
DBA_SQL_PLAN_BASELINES表统一管理,强制生效 - RAC 中若某节点因临时统计信息偏差生成劣质计划,Outline 无法拦截该计划进入库缓存;SPM 的
ENABLED=NO+ACCEPTED=NO状态可确保其永不被选中 - 19c 默认启用
optimizer_capture_sql_plan_baselines=TRUE,但 RAC 下需确认所有实例该参数一致,否则部分节点可能漏捕获
捕获基线时必须避开的三个 RAC 特有陷阱
在 RAC 中直接运行 DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE 很危险:它只从当前连接实例的库缓存加载,若目标 SQL 最近只在 node2 执行过,node1 上执行该过程将返回 0 行,导致基线缺失。
- 优先用
LOAD_PLANS_FROM_SQLSET:先用DBMS_SQLTUNE.CREATE_SQLSET跨实例收集V$SQL,再统一加载,确保覆盖所有节点的活跃计划 - 避免在高并发窗口执行捕获:RAC 中
DBA_SQL_PLAN_BASELINES是全局对象,写入 SYSAUX 表空间时存在争用,建议在业务低峰期批量操作 - 检查
origin字段:基线来源为MANUAL-LOAD才可控;若为AUTO-CAPTURE,需确认optimizer_capture_sql_plan_baselines在所有实例均为TRUE,否则节点间基线不全
演进(evolve)阶段如何防止 RAC 节点行为不一致
执行 DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE 时,默认只在当前实例验证新计划性能。若 node1 验证通过但 node2 因缓存压力或 I/O 延迟导致验证失败,会出现部分节点用新计划、部分仍用旧计划的割裂状态。
- 必须显式指定
verify=>TRUE且commit_stage=>TRUE,否则仅生成报告不自动接受 - 验证前先在所有节点运行
ALTER SYSTEM FLUSH SHARED_POOL,清空旧游标,避免验证时复用残留的劣质执行计划 - 验证后立刻查
DBA_SQL_PLAN_BASELINES中ACCEPTED和ENABLED状态,RAC 下二者必须同时为YES才算真正生效
最易被忽略的一点:SPM 基线不解决统计信息陈旧问题。如果某张表三个月没收集统计信息,即使基线锁定的是“最优”计划,那个“最优”也是基于过期数据算出来的。在 RAC 中,DBMS_STATS.GATHER_TABLE_STATS 必须配合 force=>TRUE 和 degree=>DBMS_STATS.AUTO_DEGREE,否则默认只在发起节点收集,其他节点统计信息仍滞后。











