oracle 21c执行计划突变主因是统计信息陈旧与新优化机制(基数反馈、自适应计划)共同作用;需优先校验a-rows与e-rows偏差、更新join列统计信息并禁用激进特性。

Oracle 21c 的 CBO 对 JOIN 顺序、驱动表选择和访问路径的估算更激进,执行计划突变不是 bug,而是统计信息 + 新优化规则共同作用的结果;不更新统计信息或忽略绑定变量窥探失效,90% 的“突变”其实早有征兆。
为什么刚升级/改数据后执行计划就变了?
Oracle 21c 的优化器引入了更敏感的基数反馈(Cardinality Feedback)和自适应执行计划(Adaptive Plans)默认启用机制。一旦某次执行发现预估行数严重偏离实际(比如预估 1 行,实际返回 10 万行),它可能在后续硬解析时直接切换 JOIN 算法(如从 NESTED LOOPS 切到 HASH JOIN),甚至重排 JOIN 顺序。
- 典型诱因:基表统计信息陈旧,特别是大表的
NUM_ROWS和AVG_COL_LEN偏差 >15% - 隐性触发:使用绑定变量时,首次执行用的是窥探值(peeked value),后续同 SQL 若传入高选择性值,CBO 仍沿用旧基数估算
- 21c 特有行为:对
VECTOR_DISTANCE或JSON_VALUE参与的 JOIN,优化器可能放弃传统代价模型,转而依赖运行时采样,导致计划不稳定
如何快速定位突变点而非盲目 hint?
别先加 /*+ USE_HASH */ —— 先确认是不是统计偏差或谓词被错误下推。关键看两处输出:
- 查
V$SQL_PLAN中同一SQL_ID的多条记录,对比PLAN_HASH_VALUE和OTHER_XML里的cardinality字段,确认哪一步预估崩了 - 执行
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('your_sql_id', NULL, 'ALLSTATS LAST')),重点看A-Rows(实际行数) vsE-Rows(预估行数)是否相差 2 个数量级以上 - 若发现
JOIN FILTER CREATE或JOIN FILTER USE操作符大量出现,说明优化器正在尝试并行自适应过滤,但数据倾斜导致效果反噬
稳定 JOIN 计划的实操底线操作
强制固定不是目的,让 CBO “算得准”才是根本。以下三步缺一不可:
- 对所有 JOIN 涉及的表(含中间视图),立即执行
DBMS_STATS.GATHER_TABLE_STATS,加上method_opt => 'FOR ALL COLUMNS SIZE AUTO'和degree => 4(避免单线程收集拖慢响应) - 禁用可能导致误判的自动特性:在会话级执行
ALTER SESSION SET "_optimizer_adaptive_plans" = FALSE(仅限已确认问题场景,非全局) - 对关键 JOIN 条件列,检查是否存在隐式类型转换——例如
WHERE t1.id = t2.id_char(t2.id_char是 VARCHAR2),这会让索引失效且基数估算完全失真
最常被跳过的动作:验证 JOIN 列上是否有函数索引或虚拟列索引。Oracle 21c 在面对 UPPER(t1.name) = UPPER(t2.name) 这类条件时,若只建了普通 B-Tree 索引,它宁可全表扫描也不会用索引,但你未必会在执行计划里看到警告。











