refresh fast on commit是唯一实现基表提交即增量更新的配置,但需日志含sequence和rowid、mv定义严格匹配规则、避免truncate导致snaptime$$失效,否则静默降级或报错。

REFRESH FAST ON COMMIT 是唯一能实现“基表一提交、物化视图立刻增量更新”的配置方式。但这个组合极容易失败——不是语法写错,而是底层依赖链稍有不匹配,Oracle 就静默降级为 ON DEMAND 或直接报错。
建日志必须带 SEQUENCE 和 ROWID
REFRESH FAST ON COMMIT 要求物化视图日志具备变更序列追踪能力,缺一不可:
- ROWID 用于定位被修改的行
- SEQUENCE 用于保证多行变更的顺序一致性
不加这两项,哪怕物化视图定义里写了 ON COMMIT,Oracle 也会拒绝创建,报 ORA-12052
示例正确写法:CREATE MATERIALIZED VIEW LOG ON emp WITH SEQUENCE, ROWID (empno, ename, deptno) INCLUDING NEW VALUES;注意:
INCLUDING NEW VALUES 在涉及 UPDATE 场景时不能省,否则旧值丢失导致增量逻辑断裂
物化视图定义必须显式声明 REFRESH FAST ON COMMIT
只写 REFRESH FAST 或 REFRESH FORCE ON COMMIT 都不行:
- REFRESH FAST 缺少触发时机,Oracle 默认按 ON DEMAND 处理
- REFRESH FORCE ON COMMIT 会先尝试 FAST,失败就退到 COMPLETE,但 COMPLETE 不支持 ON COMMIT 模式,最终整个语句会报 ORA-12054
正确写法必须是:CREATE MATERIALIZED VIEW mv_emp_dept REFRESH FAST ON COMMIT AS SELECT e.empno, e.ename, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno;且要求
JOIN 类型只能是 INNER 或受限的 LEFT OUTER;含 FULL OUTER、RIGHT OUTER、ROWNUM、SYSDATE 等任意一项,FAST ON COMMIT 直接不可用
验证是否真生效,别信“创建成功”
创建成功不等于ON COMMIT 生效,必须查两个地方:
- SELECT CAN_USE_LOG, STALENESS, LAST_REFRESH_DATE FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MV_EMP_DEPT';
若 CAN_USE_LOG = 'NO',说明日志不匹配或查询不满足规则
- SELECT LOG_TABLE, MASTER, ROWIDS, SEQUENCE FROM DBA_MVIEW_LOGS WHERE MASTER = 'EMP';
确认 ROWIDS = 'YES' 且 SEQUENCE = 'YES'
更直接的验证:往基表插一条数据并 COMMIT,立刻查物化视图——如果没出现新数据,说明 ON COMMIT 实际未触发,大概率已降级为手动刷新模式
常见静默失效点:基表被 TRUNCATE 过
TRUNCATE 会清空 MLOG$_xxx 日志表,但不会重置日志内部的 SNAPTIME$$ 水位线。下次 ON COMMIT 刷新时,Oracle 发现日志里没有“自上次水位以来的变更”,直接报 ORA-12034 并停止刷新,且不抛异常到客户端
此时必须人工干预:UPDATE MLOG$_emp SET SNAPTIME$$ = SYSDATE WHERE SNAPTIME$$ = TO_DATE('4000-01-01', 'YYYY-MM-DD');
否则物化视图将永远卡在 STALE 状态,后续所有 COMMIT 都无法驱动刷新
真正让 REFRESH FAST ON COMMIT 稳住的,从来不是语法写对了,而是日志字段、基表约束、MV 查询结构、甚至 DML 历史(比如有没有 TRUNCATE)全部对齐。漏掉任意一环,它就变成一个看起来能跑、实际不工作的空壳。











