FAST刷新静默退化为COMPLETE是因底层条件断裂自动降级:日志缺ROWID/SEQUENCE、状态INVALID、基表MOVE重置ROWID,或SQL含非确定性表达式、JOIN漏ROWID别名、聚合字段未全列于SEQUENCE,均导致不报错只全表重算。

FAST 刷新静默退化为 COMPLETE,不是 Oracle “故意不快”,而是底层条件断裂后自动降级——它不报错、不警告,只默默扫全表重算。
查日志状态:MLOG$_xxx 缺字段或失效就退化
FAST 刷新依赖物化视图日志(MLOG$_xxx)记录增量变更,一旦日志缺失关键字段或状态异常,刷新引擎当场放弃增量逻辑:
- SELECT rowids, sequence$$ FROM USER_MVIEW_LOGS WHERE master = 'T1' 返回 rowids = 'NO' → 日志没建 WITH ROWID,哪怕 SQL 里写了 t1.ROWID t1_rid 也白搭
- SEQUENCE$$ = 'NO' → 日志没带 SEQUENCE(...),无法排序变更顺序,增量不可靠
- 日志表 MLOG$_T1 的 STATUS = 'INVALID' 或 MASTER_OBJECT_ID 与基表不一致 → 日志已断裂,但 DBA_MVIEWS.FAST_REFRESHABLE 仍可能显示 'YES',实则运行时必退化
- 基表刚执行过 ALTER TABLE ... MOVE 或 SHRINK SPACE → ROWID 重置,旧日志失效,必须重建日志
看物化视图定义:SQL 超出支持范围就 fallback
Oracle 对FAST 刷新的 SQL 有硬性限制,不满足就直接走 COMPLETE,且不提示具体哪条违规:
- SELECT *、SYSDATE、ROWNUM、UPPER(col)、col + 1 等非确定性表达式 → DBMS_MVIEW.EXPLAIN_MVIEW 返回 REFRESH_FAST_POSSIBLE = 'NO'
- 多表 JOIN 中漏写某张表的 ROWID 别名(如只写了 t1.ROWID t1_rid,漏了 t2.ROWID t2_rid)→ 整个 MV 不可快速刷新
- 聚合物化视图中,GROUP BY 字段未全部包含在日志的 SEQUENCE() 列表里 → 增量聚合无法还原,只能重算
- 嵌套 MV 场景下,上游 MV 被 COMPLETE 刷新过,下游未先做一次 COMPLETE → 下次 FAST 必报 ORA-12047,但若用 FORCE 就静默走全量
调用参数陷阱:atomic_refresh=TRUE 加剧全表扫描
即使日志和 SQL 都合规,atomic_refresh => TRUE(默认值)也会让 FAST 刷新实际执行路径变重:
- 它强制在单事务内完成:先 DELETE 旧数据,再 INSERT /*+ APPEND */ 新数据
- 为保证一致性读(consistent read),Oracle 必须提前扫描基表所有可能参与变更的行构造前镜像 → 即使查询带 WHERE 条件,谓词也无法下推,最终仍是全表扫描后再过滤
- 典型现象:v$session.event 出现大量 db file sequential read 和 enq: TX 等待,执行计划里 TABLE ACCESS FULL 明晃晃挂着
- 解法是显式传 atomic_refresh => FALSE,改用 TRUNCATE + INSERT /*+ APPEND */,但注意:备库上会触发 ORA-16000,只能在主库执行
真正难察觉的是日志“看似存在、实则失效”——比如 MLOG$_T1 表还在,但 MASTER_OBJECT_ID 指向一个已被 DROP 后重建的同名表,这种断裂不会报错,FAST 却永远无法启用。


















