FAST刷新并非默认生效,需严格满足日志、定义、权限等前置条件;任一缺失即静默降级为COMPLETE,唯一可靠判断依据是查询DBA_MVIEWS.FAST_REFRESHABLE字段。

Oracle 物化视图的 FAST 刷新不是“开了就能用”的功能,它依赖一整套严格匹配的前置条件。只要其中任一环节不满足,DBMS_MVIEW.REFRESH(..., method => 'F') 就会静默退化为 COMPLETE,而你可能完全不知道——查 DBA_MVIEWS.FAST_REFRESHABLE 才是唯一可靠判断依据。
必须先建物化视图日志,且字段和选项要严丝合缝
物化视图日志不是可选组件,而是 FAST 刷新的底层数据源。它不是自动创建的,也不能靠“大概对”蒙混过关。
-
CREATE MATERIALIZED VIEW LOG ON t WITH ROWID, PRIMARY KEY INCLUDING NEW VALUES;是最常见写法,但要注意:PRIMARY KEY要求基表真有主键(或唯一约束+NOT NULL),否则日志虽能建成功,后续 FAST 仍失败 - 如果物化视图 SQL 中涉及
UPDATE或DELETE,必须加SEQUENCE(col1, col2)——只写SEQUENCE不带列名 Oracle 会报错;列名必须覆盖所有被物化视图引用的字段(包括WHERE和GROUP BY中的) -
INCLUDING NEW VALUES不可省略。漏掉它,UPDATE操作只会记录新值,旧值丢失,导致增量计算逻辑断裂 - 建完立刻验证:
SELECT * FROM MLOG$_t WHERE SNAPTIME$$ = TO_DATE('4000-01-01', 'YYYY-MM-DD');若返回空行,说明日志未被 MV 刷新机制识别,常见于建日志时误用了COMMIT SCN模式
物化视图定义本身必须满足“可快速刷新语义”
即使日志完美,物化视图 SQL 的写法稍有越界,FAST 就直接失效。Oracle 不报错,只把 DBA_MVIEWS.FAST_REFRESHABLE 设为 NO。
- 禁止出现:
SYSDATE、ROWNUM、DBMS_RANDOM、子查询中嵌套聚合+分析函数(如ROW_NUMBER() OVER (...) + SUM()) - 多表连接场景下:所有被 JOIN 的基表都必须有对应物化视图日志;日志中必须包含该表在 MV 查询里出现的所有列(含
SELECT、JOIN、WHERE、GROUP BY中的);且所有日志都得带ROWID和INCLUDING NEW VALUES - 带
GROUP BY的聚集 MV:必须显式写COUNT(*)(不能只写SUM(x));SELECT列必须包含全部GROUP BY列;不能有HAVING - 远程物化视图(通过 DB Link):目标库上的 MV 定义中不能含本地函数或上下文变量(如
SYS_CONTEXT),否则无法映射到源库日志的ROWID
刷新执行时的真实行为,得靠日志和元数据交叉验证
调用 DBMS_MVIEW.REFRESH 后,别信“执行成功”就等于增量生效。真正是否走 FAST,要看变更是否被消费。
- 刷新后立即查:
SELECT COUNT(*) FROM MLOG$_t WHERE SNAPTIME$$ > (SELECT LAST_REFRESH_DATE FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MY_MV');结果非零,才说明有增量数据被读取并应用 - 如果基表被
TRUNCATE过,MLOG$_t被清空但SNAPTIME$$水位线没重置,下次FAST会因找不到“上次快照点”而报ORA-12034——此时必须人工UPDATE MLOG$_t SET SNAPTIME$$ = ...修复 - 多个 MV 共享同一张基表日志时,只要其中一个 MV 定义里漏了某列(比如日志含
col_a,但某个 MV 查询没选它),所有依赖该日志的 MV 的FAST_REFRESHABLE都会被设为NO -
method => 'F'不保证一定 FAST;method => 'C'强制全量;method => 'F'实际走什么,取决于当前 MV 定义和日志状态的实时校验结果
最常被忽略的点是:物化视图日志的 SNAPTIME$$ 字段本质是每个 MV 自己维护的水位线,不是全局时间戳。它一旦因异常中断(如网络断开、权限不足、磁盘满)而卡住,就不会自动推进——后续所有 FAST 请求都会反复失败,直到人工干预。这不像流处理系统有 checkpoint 重放机制,Oracle 的增量链是脆弱且不可自愈的。


















