oracle不会自动物理删除mlog$_表行,仅用snaptime$$标记已消费;直接truncate/delete/drop会破坏一致性,应分批调用dbms_mview.purge_log清理并重建(snaptime$$,sequence$$)索引、更新统计信息。
oracle 不会自动物理删除 mlog$_ 表里的行
物化视图日志表(mlog$_xxx)不是普通日志文件,而是一张持久化的关系表。oracle 仅用 snaptime$$ 字段标记某条记录“已被消费”,从不触发物理删除——哪怕所有关联的物化视图都已完成刷新,百万条旧记录仍原地不动。高水位线(hwm)卡死,空间不释放,后续查询和刷新持续全表扫描。
直接 TRUNCATE 或 DELETE FROM mlog$_xxx 会出问题
硬删破坏 Oracle 内部一致性机制:
-
TRUNCATE后 HWM 下降但段头块残留结构信息,后续插入可能异常扩展,甚至触发ORA-00604 -
DELETE全表锁表、撑爆 UNDO、易被长事务阻塞,且不解决索引碎片问题 -
DROP TABLE sys.mlog$_xxx直接损坏数据字典,后续建同名日志大概率报ORA-12003或ORA-12083
DBMS_MVIEW.PURGE_LOG 为什么没效果
调了过程但表体积不变,常见原因有三个:
- 存在未注销的残留物化视图:查
DBA_REGISTERED_SNAPSHOTS和DBA_BASE_TABLE_MVIEWS,只要任一 MV 的LAST_REFRESH_DATE比日志里最小snaptime$$还晚,PURGE_LOG就跳过清理 - 多个 MV 共享同一日志,其中某个长期停摆(比如 6 个月没刷新),那这 6 个月的所有日志都会被保留
- 传入的保留天数(如 30)大于实际最老未消费时间:它只清“已确认可删”的窗口,不会强制截断
真正有效的收缩路径只有两条
一是安全清理 + 索引重建:
- 先确认无残留 MV:
SELECT * FROM DBA_REGISTERED_SNAPSHOTS WHERE LOG_OWNER = 'SCHEMA' AND LOG_NAME = 'MLOG$_XXX' - 再分批执行:
BEGIN DBMS_MVIEW.PURGE_LOG('MASTER_TABLE', 7); COMMIT; END; - 立刻更新统计信息:
DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'MLOG$_XXX') - 必须补上关键索引:
CREATE INDEX idx_mlog_snap_seq ON mlog$_xxx (snaptime$$, sequence$$),否则刷新仍全表扫描
二是在线重定义(不影响基表业务):要求 Oracle ≥ 10g 且 compatible ≥ 10.0.0.0,用 DBMS_REDEFINITION 重建日志表结构,但需提前准备空闲空间和足够权限。
最常被忽略的是:清理完数据不建索引、不更新统计信息,结果刷新性能毫无改善——日志表收缩 ≠ 刷新变快,两者必须同步做。











