COMPLETE刷新不消费MLOG$_日志,导致SNAPTIME$$停滞、日志持续堆积;切回FAST时集中处理积压变更,引发REDO爆发式增长。

完全刷新(REFRESH COMPLETE)本身就会清空物化视图基表并全量重插,这会产生大量 INSERT REDO;更关键的是,它**不消费也不推进物化视图日志(MLOG$_xxx)里的变更记录**,导致日志持续堆积,后续一旦切回 FAST 刷新,积压的变更会集中爆发——这才是归档日志暴增的真正导火索。
为什么 REFRESH COMPLETE 会让 MLOG$_xxx 越积越多
物化视图日志的消费机制是“按水位线推进”:每次 FAST 刷新成功后,Oracle 会把 MLOG$_xxx.SNAPTIME$$ 更新为当前时间点,表示“这个时间点之前的所有变更已被处理”。而 COMPLETE 刷新完全绕过这套机制——它不读日志、不更新 SNAPTIME$$,只是简单 truncate + insert。结果就是:
-
MLOG$_xxx表持续接收源表 DML 产生的新记录,SNAPTIME$$却永远卡在上次FAST刷新的时间 - 日志表体积膨胀,每条
INSERT还自带独立 REDO(尤其当MLOG$_xxx是LOGGING状态时) - 若之后执行
DBMS_MVIEW.REFRESH(..., 'F'),Oracle 会尝试一次性消费所有积压变更,瞬间触发海量MERGE/UPDATE,REDO 爆发式增长
紧急情况下如何安全清空积压日志
别直接 TRUNCATE MLOG$_xxx——这会破坏内部快照一致性,下次 FAST 刷新大概率报 ORA-12034。正确做法是用 Oracle 官方接口清理:
- 先确认积压量:
SELECT COUNT(*) FROM MLOG$_big_table WHERE SNAPTIME$$ = TO_DATE('4000-01-01', 'YYYY-MM-DD')(未被消费的记录都标为此时间) - 执行安全清理:
EXEC DBMS_MVIEW.PURGE_LOG('BIG_TABLE'),它会同步重置SNAPTIME$$并清理元数据 - 如果日志表已严重膨胀且业务允许短暂停写,可临时设为
NOLOGGING:ALTER TABLE MLOG$_big_table NOLOGGING(之后必须补一次成功FAST刷新,否则日志状态异常)
长期规避策略:禁止无条件使用 COMPLETE 刷新
除非源表结构变更或日志损坏等极端情况,否则不应主动触发 COMPLETE。日常维护中应:
- 把自动刷新作业强制限定为
FAST模式,例如:REFRESH FAST ON DEMAND或REFRESH FAST START WITH ... NEXT ... - 监控
DBA_MVIEWS.FAST_REFRESHABLE字段,值为NO时立刻排查(常见原因:物化视图 SQL 含SYSDATE、基表被TRUNCATE、日志列缺失) - 对高频更新的源表,日志创建时严格精简字段:
WITH ROWID (id, status)而非全字段,禁用INCLUDING NEW VALUES(除非物化视图逻辑明确依赖旧值)
最易被忽略的一点:即使你从不手动执行 REFRESH COMPLETE,某些运维操作也会隐式触发它——比如用 ALTER MATERIALIZED VIEW ... COMPILE 重新编译物化视图,或通过 OEM 点击“刷新”按钮却没指定模式。任何可能绕过日志水位线的操作,都会让归档日志风险悄然累积。


















