物化视图日志必须显式创建且绑定基表,ON COMMIT刷新依赖其存在;建日志需指定WITH PRIMARY KEY、INCLUDING NEW VALUES等关键参数,否则FAST刷新失败或降级为COMPLETE。
物化视图日志必须在基表上显式创建,否则 ON COMMIT 刷新会失败
物化视图日志不是自动产生的,哪怕你只建一个 on commit 刷新的物化视图,也得先手动建日志。没它,refresh 会直接报错 ora-12004: refresh fast cannot be used 或更直白的 ora-12006: a materialized view log already exists on the table(注意这个错误其实是“日志存在但不满足要求”,不是“不存在”)。
关键点:日志绑定的是基表,不是物化视图;一个基表可被多个物化视图共享同一个日志,只要字段需求兼容。
- 建日志前确认基表有主键(
WITH PRIMARY KEY是最常用且推荐的选项) - 如果物化视图要查
ROWID,日志必须带WITH ROWID;但 Oracle 12c+ 默认启用ROWID跟踪,所以多数情况不用显式写 - 如果物化视图含聚合或
GROUP BY,日志必须包含对应列,且需INCLUDING NEW VALUES(否则FAST刷新会退化成COMPLETE)
CREATE MATERIALIZED VIEW LOG ON 表名的常见参数组合与陷阱
参数选错,轻则刷新变慢,重则 FAST 刷新完全不可用。Oracle 对日志结构非常敏感,尤其是涉及 JOIN 或 AGGREGATE 的物化视图。
-
WITH PRIMARY KEY:90% 场景够用;但若基表主键是复合主键,且物化视图只引用其中一部分列,仍可能触发ORA-12033(无法使用过滤器) -
INCLUDING NEW VALUES:必须加!尤其当物化视图含SUM()、COUNT(*)等聚合函数;漏掉它会导致FAST刷新拒绝执行,降级为COMPLETE - 不要随便加
SEQUENCE:除非物化视图定义里明确用了SEQUENCE关键字(极少场景),否则纯属冗余,还占空间 - 日志建好后,别手动删基表上的索引——
MLOG$_xxx日志表依赖基表主键索引,删了索引可能导致后续 DML 报ORA-00600内部错误
为什么 ALTER TABLE ADD CONSTRAINT 主键后,物化视图日志不生效?
Oracle 不会自动把已有日志升级适配新主键。即使你后来给基表加了主键,之前建的 WITHOUT PRIMARY KEY 日志依然无效——FAST 刷新照样失败。
- 必须先
DROP MATERIALIZED VIEW LOG ON 表名,再重建带WITH PRIMARY KEY - 重建日志不会清空已有的 DML 记录,但会重置日志内部序列号;如果物化视图正在使用中,建议在低峰期操作
- 检查日志是否生效:查
USER_MVIEW_LOGS视图,确认PRIMARY_KEY = 'YES'且LOG_TABLE字段非空 - 特别注意分区表:如果基表是分区表,日志默认不继承分区属性,
FAST刷新可能因跨分区更新而失效
物化视图日志占用空间大,能定期清理吗?
不能直接 truncate 或 delete MLOG$_xxx 表——这是 Oracle 内部管理的日志结构,删数据会破坏一致性,下次刷新大概率报 ORA-12008 或卡死。
- 真正可控的清理方式只有两种:
DBMS_MVIEW.REFRESH成功后,日志中已应用的记录由 Oracle 自动标记为可复用;或执行ALTER MATERIALIZED VIEW LOG ON 表名 PURGE(仅 12cR2+ 支持) -
PURGE不是删全部,而是按 SCN 清理已提交且被所有依赖物化视图消费过的记录;执行前务必确认没有未刷新的 MV - 长期不刷新的物化视图会让日志无限膨胀;建议监控
USER_MVIEW_LOGS.LOG_TABLE对应的表大小,超过基表 20% 就该排查刷新链路是否中断
最麻烦的其实是多层嵌套物化视图:A → B → C,B 的日志既要服务 A 又要服务 C,任意一环刷新滞后,整个日志就卡住不动。这种场景下,PURGE 得逐级确认,顺序错了反而引发连锁失败。










