最直接原因是关联的物化视图未刷新或已失效但未注销;Oracle仅清理DBA_REGISTERED_MVIEWS中CAN_USE_LOG='YES'且仍注册的物化视图所对应日志,远程MV因网络、DB Link失效等停止刷新会导致日志持续堆积。
怎么判断哪些物化视图日志卡住了
物化视图日志(mlog$_*)长期不收缩,最直接原因是关联的物化视图没刷新,或已失效但未注销。oracle 不会自动清理“无人认领”的日志记录——它只信任 dba_registered_mviews 里还注册着、且 can_use_log = 'yes' 的物化视图。一旦远程物化视图因网络中断、db link 失效、测试库下线等原因停止刷新,日志就只能越积越多。
查卡住的日志表,先看数据量:
SELECT tname, (SELECT COUNT(*) FROM <code>tname</code>) cnt FROM tab WHERE tname LIKE 'MLOG$%';
再关联注册信息,找“有日志但无有效 MVIEW”的组合:
-
SELECT m.owner, m.name, m.mview_site, m.snapid FROM dba_registered_mviews m WHERE m.name NOT IN (SELECT object_name FROM dba_objects WHERE object_type = 'MATERIALIZED VIEW');—— 找出已删 MVIEW 但注册残留的 -
SELECT log_table, master, last_refresh FROM dba_mview_logs;配合last_refresh字段看是否长时间没更新 - 重点盯
SNAPID:它是物化视图在日志消费中的唯一凭证,后续 purge 必须用到
如何安全地解除绑定并清理日志
不能直接删 MLOG$_* 表,也不能 truncate——Oracle 日志机制依赖内部标记(如 SNAPTIME$$、DMLTYPE$$ 和 OLD_NEW$$),硬删会导致后续刷新报 ORA-12034 或 ORA-12091。
正确路径是:先注销无效物化视图 → 再 purge 对应日志 → 最后确认日志表收缩。关键函数只有两个:DBMS_MVIEW.UNREGISTER_MVIEW 和 DBMS_MVIEW.PURGE_MVIEW_FROM_LOG。
-
EXEC DBMS_MVIEW.UNREGISTER_MVIEW('OWNER', 'MV_NAME', 'MVIEW_SITE');——MVIEW_SITE必须和DBA_REGISTERED_MVIEWS.MVIEW_SITE完全一致(含大小写、域名、端口),否则报 ORA-12006 -
EXEC DBMS_MVIEW.PURGE_MVIEW_FROM_LOG('OWNER', 'MASTER_TABLE_NAME', SNAPID);——SNAPID来自上一步查出的DBA_REGISTERED_MVIEWS.SNAPID,不是随便填的数字 - 执行前务必在 SESSION 级加锁基表:
LOCK TABLE <master_table> IN EXCLUSIVE MODE;,防止 purge 过程中发生 DML 干扰内部时间戳判断
为什么 PURGE 后日志表还是没变小
PURGE_MVIEW_FROM_LOG 实际做的是逻辑清理:它把 MLOG$_* 中早于该 SNAPID 最后已知刷新时间(SNAPTIME$$)的记录标为可删除,但不会立即释放空间。高水位(HWM)还在,表大小不变是正常现象。
真正释放空间要靠后续的 segment 回收动作:
- 如果是 ASSM 表空间,等下次物化视图刷新(哪怕只刷一条)会触发自动 HWM 下降
- 如果等不及,手动 shrink:
ALTER TABLE <code>MLOG$_TBL</code> SHRINK SPACE CASCADE;(需行移动启用) - 注意:不要用
TRUNCATE,它会重置SNAPTIME$$,导致所有现存注册 MVIEW 下次刷新失败
远程物化视图场景最容易漏掉的三件事
当物化视图建在另一台数据库(通过 DB Link),注销和清理比本地复杂得多,90% 的残留日志问题都出在这里。
- 注销时
MVIEW_SITE必须写完整连接串,比如'user@dblink_name',而不是只写'dblink_name';否则UNREGISTER成功但实际没生效 - 主库上查不到远程 MVIEW 的
OBJECT_NAME,所以dba_objects查询会漏判——得依赖DBA_REGISTERED_MVIEWS+ 网络连通性验证 - purge 前没停掉其他数据库的刷新请求:只要还有别的库连着这个 DB Link 刷数据,
PURGE_MVIEW_FROM_LOG就可能被并发刷新打断,日志清理不彻底
最稳妥的做法是:先关监听或防火墙拦截远端 IP,再操作;purge 完立刻查 MLOG$_* 的 COUNT(*),别只看表大小。










