物化视图日志暴增的根本原因是刷新滞后导致增量记录未被消费。常见于高频DML、未启用FAST刷新或刷新作业阻塞/失败;日志表无自动清理机制,仅在成功FAST刷新后按SNAPTIME$$安全删除旧记录。
物化视图日志(MLOG$_)为什么会突然暴增?
根本原因不是“日志太多”,而是“没被及时消费”——物化视图刷新滞后,导致日志表持续堆积。你看到的 mlog$_tblname 表体积飙升,本质是增量变更记录卡在那儿没人收。常见触发场景包括:源表高频 dml(如每秒数百次 update)、物化视图未启用 fast 刷新、或刷新作业被阻塞/失败但无人告警。
特别注意:dba_mview_logs 视图里 LOG_TABLE 字段指向的那张日志表,它本身没有自动清理机制;Oracle 只在成功执行一次 FAST 刷新后,才根据 SNAPTIME$$ 和 DMLTYPE$$ 标记安全删除旧记录。一旦刷新中断,日志就只进不出。
怎么快速定位日志堆积是否已失控?
别等 SYSTEM 或用户表空间爆满再查。直接用这两条语句看真实压力:
-
SELECT log_table, master, rowids, primary_key, filter_columns FROM dba_mview_logs WHERE master = 'YOUR_TABLE_NAME';—— 确认日志是否启用了ROWID或PRIMARY KEY,二者影响刷新能力和清理效率 -
SELECT COUNT(*) FROM MLOG$_YOUR_TABLE_NAME;—— 如果结果 > 10 万且持续上涨,基本可判定消费严重滞后
补充一个关键点:日志表默认建在源表所在表空间,但很多 DBA 忘了它可能继承 LOGGING 属性——高并发 INSERT 进日志表本身就会产生大量 REDO,进一步拖慢刷新速度,形成恶性循环。
如何防止日志表撑爆表空间?三个实操动作
不是加空间,而是控增长 + 加消费 + 降开销:
- 立刻停掉无效刷新作业:检查
dba_jobs或dba_scheduler_jobs中状态为BROKEN的物化视图刷新任务,DBMS_MVIEW.REFRESH失败后不会自动重试,得人工干预 - 给日志表加清理兜底:如果业务允许短暂延迟,可定期运行
DBMS_MVIEW.PURGE_LOG(注意参数num_days是按SNAPTIME$$时间戳删,不是系统时间) - 紧急情况下收缩日志表:先
ALTER TABLE MLOG$_XXX NOLOGGING;,再TRUNCATE TABLE MLOG$_XXX;—— 但必须确保之后能立即跑通一次完整FAST刷新,否则会丢变更
为什么开了物化视图日志,FAST 刷新还是失败?
最常踩的坑是“以为建了日志就万事大吉”。FAST 刷新实际依赖三要素同时满足:
- 源表有可用的物化视图日志(
dba_mview_logs中LOG_TABLE存在且状态正常) - 物化视图定义中明确指定
REFRESH FAST ON COMMIT或ON DEMAND,且未含不支持 FAST 的 SQL 特性(如SELECT *、聚合不含GROUP BY、跨库链接) - 刷新时用户有
SELECT源表和日志表的权限,且日志表上无未提交事务锁住SNAPTIME$$
一个典型错误:用 CREATE MATERIALIZED VIEW ... AS SELECT * FROM t; 创建 MV,即使日志存在,Oracle 也无法推导出主键/ROWID 映射关系,强制退化为 COMPLETE 刷新,日志永远不被消费。
真正难处理的不是日志多,而是日志“假死”——看起来在写入,但刷新逻辑卡在某条脏数据或权限校验上,表面安静,底下膨胀。盯住 dba_mview_logs 的 LAST_PURGE_DATE 和 LAST_REFRESH_DATE 是否同步更新,比看表大小更早发现问题。

















