只有当两个系统视图查询均为空时才能安全删除mlog$_表:dba_registered_snapshots中无注册记录且dba_mview_logs中无共享引用;必须用drop materialized view log on owner.table_name,禁用truncate/drop table及delete操作。

确认 MLOG$_ 表是否真能删
不能只看有没有物化视图存在,必须交叉查两个系统视图:
– SELECT * FROM DBA_REGISTERED_SNAPSHOTS WHERE LOG_OWNER = 'SCHEMA_NAME' AND LOG_NAME = 'MLOG$_TABLE_NAME':返回空才说明没 MV 正在注册使用该日志
– SELECT LOG_TABLE, MASTER, ROWIDS, PRIMARY_KEY FROM DBA_MVIEW_LOGS WHERE LOG_TABLE = 'MLOG$_TABLE_NAME':确认该日志未被其他 MV 共享引用(注意多个 MV 可共用一个日志)
任一查询有结果,都代表还有活跃依赖,硬删会导致后续刷新报 ORA-12003 或 ORA-12083
用 DROP MATERIALIZED VIEW LOG 而不是 TRUNCATE/DROP TABLE
TRUNCATE TABLE sys.mlog$_xxx 看似快,但会残留段头元信息,后续插入可能触发 ORA-00604;DROP TABLE sys.mlog$_xxx 直接破坏数据字典,再建同名日志大概率报 ORA-12083。
正确做法是:
– 指定基表名,不是日志表名:DROP MATERIALIZED VIEW LOG ON owner.table_name
– 跨 schema 必须写全:DROP MATERIALIZED VIEW LOG ON scott.emp
– 执行前确保基表无长事务,否则操作会被阻塞
清理旧数据要用 PURGE_LOG,别手写 DELETE
直接 DELETE FROM mlog$_xxx WHERE snaptime$$ 会全表锁、撑爆 UNDO、易被长事务卡住。<br>应调用 Oracle 原生过程:<br>– 按时间窗口清理:<code>BEGIN DBMS_MVIEW.PURGE_LOG('MASTER_TABLE', 7); COMMIT; END;(保留最近 7 天)
– 若需按年份精细清理,用 PL/SQL 循环调用,每次传固定天数并 COMMIT
– 注意:PURGE_LOG 不释放空间,只逻辑删除已消费记录;若空间未回收,后续需重建日志
清理后三件事不做,等于白干
删完或 purge 后不补这三步,刷新照样慢、空间照样涨:
– 立即收集统计信息: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 → 重建日志
最常被跳过的是索引重建和统计信息更新——日志行数少了,但没索引+过期统计,刷新时照样全表扫描+磁盘排序











