MLOG$_表导致表空间碎片主因是只增不删:Oracle仅用snaptime$$标记已消费,从不物理删除行,致高水位线卡死、空块无法复用,引发逻辑与物理碎片;清理前须验证DBA_REGISTERED_SNAPSHOTS和DBA_MVIEW_LOGS以确认无残留MV引用,再分批调用PURGE_LOG或执行DROP MATERIALIZED VIEW LOG,并重建(snaptime$$,sequence$$)复合索引及更新统计信息。
物化视图日志(MLOG$_表)为什么会导致表空间碎片?
因为 mlog$_xxx 表长期只增不删:oracle 用 snaptime$$ 字段标记“已消费”,但从不物理删除行。大量 delete 操作后高水位线(hwm)卡死,后续 insert 只往 hwm 上方追加,空块无法复用,造成严重逻辑碎片和物理空间浪费——哪怕基表才 120mb,mlog$_xxx 却涨到 200gb 是典型症状。
清理前必须验证的两个关键点
直接 DROP MATERIALIZED VIEW LOG 或 PURGE_LOG 都可能出错,先确认:
- 查
DBA_REGISTERED_SNAPSHOTS:若LOG_OWNER和LOG_NAME(如MLOG$_EMP)组合无返回,说明没有活跃 MV 注册使用该日志 - 查
DBA_MVIEW_LOGS:确认该日志未被其他 MV 引用,尤其注意多个 MV 共享一个日志时,清理边界由最晚的LAST_REFRESH_DATE决定
安全清理 MLOG$_ 表碎片的实操路径
不能 TRUNCATE 或 DROP TABLE sys.mlog$_xxx——会破坏数据字典,后续建 MV 报 ORA-12003 或刷新失败。正确做法分三步:
- 若日志已完全废弃:执行
DROP MATERIALIZED VIEW LOG ON owner.table_name,这是唯一合规 DDL - 若还需保留日志但想清旧数据:用
DBMS_MVIEW.PURGE_LOG('MASTER_TABLE', 7)分批调用(比如按 7 天窗口),每次COMMIT,避免锁表和 UNDO 撑爆 - 清理后必须立刻执行
DBMS_STATS.GATHER_TABLE_STATS,否则优化器仍走全表扫描
重建索引比删数据更重要
MLOG$_xxx 默认只有主键索引,而 FAST 刷新真正依赖的是 (snaptime$$, sequence$$) 复合索引。缺失它会导致每次刷新都全表扫描 + 排序去重:
- 执行
CREATE INDEX idx_mlog_snap_seq ON mlog$_xxx (snaptime$$, sequence$$) TABLESPACE fast_io_ts - 如果原索引损坏或统计信息过期,仅重建不够,必须同步更新统计信息
- 别忽略
ATOMIC_REFRESH => FALSE的副作用:它改用TRUNCATE + INSERT /*+ APPEND */,虽降 UNDO,但要求 MV 必须支持快速刷新且不能被外键引用
真正卡住的从来不是空间大小,而是日志里堆积的未消费记录和缺失的支撑索引——这两点不处理,清完又涨回来。











