快速刷新需同时满足基表日志、物化视图定义和刷新调用三者严格条件,缺一即静默退化为完全刷新;日志须含sequence和including new values,多表连接需所有基表建匹配日志,且定义避开非确定性函数、外连接等黑名单限制。

快速刷新不是“配出来”的,而是必须同时满足基表日志、物化视图定义、刷新调用三者的严格条件;漏掉任一环节,REFRESH FAST 就会静默退化为 COMPLETE,且不报错。
先建对物化视图日志,不是随便加 ROWID 就行
日志结构必须和物化视图查询中涉及的列、操作类型、连接方式完全匹配。常见错误是只建了 WITH ROWID,却没加 SEQUENCE 和 INCLUDING NEW VALUES——尤其当物化视图含 UPDATE 或聚合时,这会导致 FAST 刷新直接失败。
- 多表连接物化视图:所有基表都必须建日志,且每张日志都要包含查询中出现的所有列(
SELECT列 +WHERE列) - 含
COUNT(*)或其他聚合:日志必须含SEQUENCE,否则无法保证变更顺序 - 含
UPDATE操作:必须加INCLUDING NEW VALUES,否则无法获取新值用于合并 - 主键 vs ROWID:优先用
WITH PRIMARY KEY;只有在基表无主键或需支持外连接时才用WITH ROWID
物化视图定义本身要避开“快速刷新黑名单”
Oracle 对快速刷新的支持非常保守,稍有越界就拒绝 FAST。最常踩的坑是语法看似合理,实则触发隐式限制。
- 不能用
SYSDATE、ROWNUM、DBMS_RANDOM等非确定性函数 - 不能用
LONG/LONG RAW类型列 - 多表连接时:若含外连接,内表连接列上必须有唯一约束;
WHERE中只能用AND连接,且只能用= - 聚合物化视图:必须显式写
COUNT(*),GROUP BY列必须全部出现在SELECT列表中 -
ON COMMIT刷新:要求所有基表日志都带SEQUENCE,且不能跨 PDB(容器数据库边界)
刷新调用时 METHOD=FAST 不等于真走快速路径
即使建对了日志、定义也合规,执行 DBMS_MVIEW.REFRESH(..., METHOD => 'FAST') 仍可能 fallback 到 COMPLETE——因为 Oracle 在运行时会动态检查日志状态、SNAPTIME$$ 值、是否缺失日志记录等。
- 检查日志是否“空”:
SELECT * FROM MLOG$_<base_table></base_table>,如果返回 0 行,说明日志未捕获到任何变更,FAST 会跳过 - 确认
SNAPTIME$$是否被重置:执行EXEC DBMS_MVIEW.REFRESH('mv_name', 'F')后,日志里对应行的SNAPTIME$$应更新为刷新时间点;若仍是01-JAN-4000,说明刷新未真正消费日志 - 用
DBMS_MVIEW.EXPLAIN_REWRITE验证:传入物化视图名和一条典型查询,看返回是否为REWRITTEN;若为UNREWRITTEN,说明快速刷新机制未被识别或已失效 - 别信
EXPLAIN PLAN:它只显示优化器计划,不反映实际刷新路径;要看V$ALL_SQL_PLAN_MONITOR中是否有TABLE ACCESS BY INDEX ROWID卡住,那是 FAST 退化的典型信号
真正难的不是写对那几条 DDL,而是每次修改基表结构、增加新字段、调整物化视图逻辑后,都要重新验证日志字段覆盖、SEQUENCE$$ 连续性、以及 SNAPTIME$$ 的推进是否正常——这些细节不暴露在错误信息里,只藏在监控视图和日志表数据中。











