Oracle物化视图FAST刷新需同时满足日志完备(ROWID、SEQUENCE、INCLUDING NEW VALUES)、MV定义无禁用语法、FAST_REFRESHABLE与CAN_USE_LOG均为YES,且人工维护时间戳水位,任一环节缺失均静默降级为全量刷新。

不能靠写 REFRESH FAST 就保证只增量刷新——Oracle 会静默降级为全量,且不报错。
物化视图日志必须显式创建且字段齐全
没有 MATERIALIZED VIEW LOG,REFRESH FAST 必然失败。常见错误是只执行 CREATE MATERIALIZED VIEW LOG ON t WITH PRIMARY KEY,但漏掉关键选项:
-
ROWID和SEQUENCE必须显式声明,否则 Oracle 无法定位变更行和还原 DML 顺序 -
INCLUDING NEW VALUES不可省略,尤其涉及UPDATE:缺它会导致旧值丢失,增量逻辑直接崩 - 时间戳字段(如
last_modified)若用于过滤,必须出现在日志列列表中,例如WITH PRIMARY KEY, ROWID (id, last_modified) INCLUDING NEW VALUES - 建完立刻查:
SELECT LOG_TABLE, SEQUENCE, ROWIDS FROM DBA_MVIEW_LOGS WHERE MASTER = 'T',确认SEQUENCE = 'YES'且ROWIDS = 'YES'
物化视图定义必须避开所有FAST禁用语法
哪怕日志全对,MV 查询里一个违规点就让 FAST_REFRESHABLE 变成 'NO',后续所有 REFRESH FAST 都静默走 COMPLETE:
- 禁止出现
SYSDATE、CURRENT_DATE、ROWNUM、子查询中的嵌套分析函数 - 禁止
ORDER BY、HAVING、外连接(LEFT JOIN等)、MAX/MIN聚合(除非配合特定结构) - 若含
GROUP BY,所有分组列必须来自基表原始列,不能是表达式(如TRUNC(create_time)→ 日志里得记create_time) - 大小写必须严格一致:日志建的是
PAY_STATUS,MV 查询里写pay_status→ 匹配失败
每次刷新前必须验证 FAST_REFRESHABLE 状态
DBMS_MVIEW.REFRESH('MV_T', 'F') 不报错 ≠ 真走增量。Oracle 检查极严,失败就降级,不提示:
- 执行前必查:
SELECT FAST_REFRESHABLE, CAN_USE_LOG FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MV_T' - 只有
FAST_REFRESHABLE = 'YES'且CAN_USE_LOG = 'YES'才可信 - 刷新后验证是否真消费了增量:
SELECT COUNT(*) FROM MLOG$_T WHERE SNAPTIME$$ > (SELECT LAST_REFRESH_DATE FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MV_T'),结果非零才算成功 - 若基表被
TRUNCATE过,MLOG$_T被清空但SNAPTIME$$未重置,下次FAST直接报ORA-12034
基于时间戳的增量必须人工维护水位
想按“昨天新增”同步,不能在 MV 定义里写动态时间函数,必须靠外部水位控制:
- 建日志时启用时间戳模式:建日志不加
WITH COMMIT SCN,Oracle 才写SNAPTIME$$ - MV 查询中写死时间值:
WHERE last_modified > TO_DATE('2026-09-03', 'YYYY-MM-DD') - 每次刷新成功后,手动更新水位表(如单行表
mv_watermark),把日期改成新值,否则下次还拉同样数据 - 若刷新中断(网络断、目标库宕),
SNAPTIME$$不会自动回滚,必须人工干预该字段,否则链断裂
真正难的不是语法,而是整个链路里任意一环出错——日志少个 ROWID、MV 多个 SYSDATE、水位没更新——都会让增量失效,且你根本收不到警告。


















