Oracle RAC统计信息不同步非bug,而是optimizer_stats_lock机制与实例间共享内存刷新延迟共同导致DBA_TAB_STATISTICS视图中last_analyzed等字段在各节点显示不一致;实际数据字典tab$.analyzetime唯一且一致,执行计划不受影响。

Oracle RAC 统计信息不同步不是数据库 bug,而是 optimizer_stats_lock 机制 + 实例间共享内存刷新延迟共同导致的表级统计信息在各节点视图中不一致——查 DBA_TAB_STATISTICS 可能返回不同 last_analyzed 时间或 num_rows,但执行计划不受影响,也不代表数据本身不一致。
为什么 DBA_TAB_STATISTICS 在不同节点看到的统计时间不一样
Oracle RAC 中统计信息本身是写入数据字典(obj$, tab$ 等)的,物理上只有一份;但每个实例的 shared pool 里会缓存一份本地副本(通过 optimizer_stats_lock 控制),用于避免频繁访问数据字典。这个缓存不是实时广播同步的。
- 当某节点执行
DBMS_STATS.GATHER_TABLE_STATS,它会更新本地缓存 + 提交到数据字典 - 其他节点仍可能沿用旧缓存,直到下次被刷出、或触发隐式刷新(如 SQL 解析时发现缓存过期)
-
last_analyzed字段从缓存读取,所以SELECT last_analyzed FROM DBA_TAB_STATISTICS在不同节点可能显示不同时间 - 这不是错误,是设计行为:降低统计信息访问对全局缓存(GCS)的压力
怎么确认统计信息是否真的“没同步”而非只是缓存差异
别只看 DBA_TAB_STATISTICS,直接比对数据字典底层值:
- 在所有节点执行:
SELECT obj#, analyzetime FROM tab$ WHERE obj# = (SELECT object_id FROM dba_objects WHERE owner='SCOTT' AND object_name='EMP'); - 如果所有节点返回的
analyzetime一致,说明统计已持久化成功,只是缓存未刷新 - 若
analyzetime不同,则说明某节点的DBMS_STATS调用失败或未提交(检查 alert.log 是否有 ORA-20000 或权限错误) - 补充验证:
SELECT /*+ NO_MONITORING */ COUNT(*) FROM SCOTT.EMP;在各节点跑一次,再查DBA_TAB_STATISTICS——多数情况下缓存会强制刷新
如何让各节点尽快看到一致的统计时间
手动刷新缓存比等自动更可控,但注意:这不是必须操作,仅用于诊断或强一致性要求场景:
- 在目标节点执行:
EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;—— 刷新监控信息缓存(间接促发统计缓存重载) - 更直接方式:
ALTER SYSTEM FLUSH SHARED_POOL;(慎用,会清空所有 SQL 执行计划) - 推荐轻量做法:在各节点执行一次针对该表的硬解析,例如:
SELECT /*+ FULL(t) */ COUNT(*) FROM SCOTT.EMP t WHERE rownum = 1; - 注意:不要依赖
DBA_TAB_STATISTICS.last_analyzed做自动化判断逻辑——它本质是“缓存快照时间”,不是权威时间戳
真正关键的是执行计划是否稳定。只要 tab$.analyzetime 一致,且 DBA_TAB_STATISTICS.num_rows 等核心字段无大幅偏差,就无需干预。强行刷 shared pool 或加锁同步反而引入不必要的抖动。


















