mlog$_表暴增源于源表dml触发日志写入且未被所有物化视图消费,导致旧记录长期滞留;清理须先验证无mv注册引用,再用dbms_mview.purge_log分批清理,并立即收集统计信息、重建snaptime$$/sequence$$索引。

为什么MLOG$_表会暴增
物化视图日志表(如 MLOG$_BIG_TABLE)本身不因刷新而写入,而是由源表的 DML 触发写入。高频 UPDATE、INSERT 或 DELETE 会逐条写入日志表;如果日志表是 LOGGING 模式(默认),每条 INSERT 就产生一份 REDO —— 这和源表 DML 的 REDO 是两份独立开销。更关键的是:只要还有任一物化视图没消费某条日志(即 snaptime$$ 未更新到该行时间戳),这条记录就永远留着。一个长期未刷新的 MV,或多个 MV 共享日志但刷新节奏错开,就会让 MLOG$_xxx 持续膨胀,哪怕当前变更极少。
查清是否真能清理
不能只看 SELECT COUNT(*) FROM MLOG$_XXX 返回值小就认为“可删”。必须交叉验证两个系统视图:
- 查
DBA_REGISTERED_SNAPSHOTS:确认LOG_OWNER和LOG_NAME(如'MLOG$_EMP')组合无返回,说明没有 MV 正在注册使用该日志 - 查
DBA_MVIEW_LOGS:确认该日志未被其他 MV 引用,尤其注意多个 MV 可共享一个日志,需逐个核对LOG_TABLE和LOG_OWNER - 执行前务必导出依赖快照:
SELECT LOG_OWNER, LOG_TABLE, MASTER, ROWIDS, PRIMARY_KEY FROM DBA_MVIEW_LOGS WHERE LOG_TABLE = 'MLOG$_EMP'
安全清理积压日志的正确方式
直接 TRUNCATE 或 DELETE FROM MLOG$_xxx 是危险操作:前者不更新 snaptime$$,Oracle 仍认为日志有效,空间很快回升;后者全表锁、撑爆 UNDO、易被长事务阻塞。应使用 Oracle 原生过程分批清理:
- 先查时间边界:
SELECT MIN(snaptime$$), MAX(snaptime$$) FROM MLOG$_xxx - 按保留天数清理:
BEGIN DBMS_MVIEW.PURGE_LOG('MASTER_TABLE', 7); COMMIT; END;(数字 7 表示保留最近 7 天) - 若需按年份清理(如只清 2023 年前),用 PL/SQL 构造循环,每次传入固定天数并
COMMIT
清理后必须立刻补的三件事
删完不是结束。以下三步缺一不可,否则刷新照样慢、空间照样不释放:
- 立即收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'MLOG$_TABLE_NAME'),否则优化器仍走全表扫描 - 检查并重建关键索引:
CREATE INDEX idx_mlog_snap_seq ON MLOG$_xxx (snaptime$$, sequence$$)——这是快速刷新扫描日志的性能命脉 - 若空间仍未释放:
MLOG$_xxx不支持SHRINK SPACE,只能导出数据 →DROP MATERIALIZED VIEW LOG ON owner.table_name→ 重建日志











