必须交叉验证dba_registered_snapshots和dba_mview_logs确认无mv引用后,方可安全清理;清理须用purge_log而非delete;删后须立即收集统计信息、重建snaptime$$/sequence$$索引。

直接删 sys.mlog$_xxx 表或 TRUNCATE 它,99% 会引发 ORA-00604、ORA-12083 或后续刷新失败——这不是权限问题,而是 Oracle 数据字典一致性被破坏的必然结果。
怎么确认 MLOG$_ 表真能删,而不是“看起来没人用”
只查 DBA_MVIEWS 或看物化视图是否存在,完全不准。必须交叉验证两个系统视图:
-
SELECT * FROM DBA_REGISTERED_SNAPSHOTS WHERE LOG_OWNER = 'SCHEMA_NAME' AND LOG_NAME = 'MLOG$_TABLE_NAME'—— 若无返回,说明没有 MV 正在注册使用该日志 -
SELECT * FROM DBA_MVIEW_LOGS WHERE LOG_TABLE = 'MLOG$_TABLE_NAME'—— 确认它没被其他 MV 引用;注意多个 MV 可共享一个日志,得逐个核对LOG_TABLE和LOG_OWNER - 执行前务必导出依赖快照:
SELECT LOG_OWNER, LOG_TABLE, MASTER, ROWIDS, PRIMARY_KEY FROM DBA_MVIEW_LOGS WHERE LOG_TABLE = 'MLOG$_TABLE_NAME'
清理旧记录别用 DELETE,用 PURGE_LOG 才安全
DELETE FROM mlog$_xxx WHERE snaptime$$ 是高危操作:全表锁、撑爆 UNDO、易被长事务阻塞,且不更新内部状态。正确方式是调用 Oracle 原生过程:
- 保留最近 7 天:
BEGIN DBMS_MVIEW.PURGE_LOG('MASTER_TABLE', 7); COMMIT; END; - 若需按年份清理(如清 2023 年前),用 PL/SQL 循环调用,每次传固定天数并
COMMIT - 多 MV 共享一个日志时,清理边界由所有 MV 中最晚的
LAST_REFRESH_DATE决定,不能只看单个 MV 的刷新时间
删完不补这三步,空间和性能照样崩
清理后立刻执行:
- 收集统计信息:
DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'MLOG$_TABLE_NAME'),否则优化器仍走全表扫描 - 重建关键索引:
CREATE INDEX idx_mlog_snap_seq ON mlog$_xxx (snaptime$$, sequence$$)—— 这是 FAST 刷新扫描日志的性能命脉 - 若空间仍未释放:
mlog$_xxx不支持SHRINK SPACE,只能导出数据 →DROP MATERIALIZED VIEW LOG ON owner.table_name→ 重建日志
真正卡住人的,从来不是日志表有多大,而是清理后忘了建索引、没更新统计信息、也没确认 snaptime$$ 是否被所有 MV 消费完毕。











