必须查dba_registered_snapshots和dba_mview_logs双视图确认日志无任何活跃mv注册或引用,才能安全清理;不可按时间删记录,因snaptime$$仅作标记、刷新依赖scn与snapid匹配,误删将导致ora-12003等刷新失败。

物化视图日志(MLOG$_ 表)不会自动物理清理,按日分区的大表一旦更新频繁,日志极易膨胀到基表体积的百倍以上——清理必须围绕「消费状态」而非「时间」来设计,否则要么删不掉,要么误删导致刷新失败。
怎么判断日志是否真能清理:查 DBA_REGISTERED_SNAPSHOTS 和 DBA_MVIEW_LOGS 双视图
不能只看有没有物化视图存在,也不能只查 DBA_MVIEWS——它不反映日志绑定关系。关键验证点有两个:
-
DBA_REGISTERED_SNAPSHOTS中查不到该日志的LOG_OWNER+LOG_NAME组合,说明没有快照在注册消费它 -
DBA_MVIEW_LOGS中该日志的LOG_TABLE字段未被其他 MV 引用;注意多个 MV 可共享一个日志,得逐个核对MASTER和LOG_TABLE - 执行前导出当前绑定:
SELECT LOG_OWNER, LOG_TABLE, MASTER, ROWIDS, PRIMARY_KEY FROM DBA_MVIEW_LOGS WHERE LOG_TABLE = 'MLOG$_ORDERS';
为什么不能按「日分区时间」直接删日志记录
日志表本身不按分区组织,snaptime$$ 是 DATE 类型但精度仅到秒,且 Oracle 刷新时依赖 SCN 和内部 SNAPID 匹配,不是简单的时间范围过滤。常见错误包括:
- 用
DELETE FROM MLOG$_ORDERS WHERE snaptime$$ :破坏日志结构一致性,后续 <code>REFRESH报ORA-12034或ORA-12091 - 以为“某日分区没更新”就代表对应日志可删:错。只要还有 MV 的
LAST_REFRESH_DATE滞后于该时间点,日志就必须保留 - 多 MV 共享日志时,清理边界由所有 MV 中最晚的
LAST_REFRESH_DATE决定,不是单个 MV 的刷新时间
安全清理的两种路径:全删 or 精准 purge
确认日志孤立后,才可操作;否则优先调用 PURGE_MVIEW_FROM_LOG 清理已消费旧记录:
- 全删日志(彻底释放):
DROP MATERIALIZED VIEW LOG ON owner.orders;—— 唯一合规 DDL,删表+索引+约束,但空间不会立即返还文件级,需后续ALTER DATABASE DATAFILE ... RESIZE - 只清旧记录(保留日志供其他 MV 使用):
BEGIN DBMS_MVIEW.PURGE_MVIEW_FROM_LOG(mvid); END;,其中mvid必须来自DBA_BASE_TABLE_MVIEWS.MVIEW_ID,不是DBA_MVIEWS - 执行
PURGE_MVIEW_FROM_LOG前务必加锁基表:LOCK TABLE orders IN EXCLUSIVE MODE;,防止 DML 干扰snaptime$$判断
按日分区场景下容易被忽略的细节
日志膨胀往往不是因为没清理,而是因为「有 MV 长期停更但未注销」。这类问题在跨库 DB Link 场景最典型:
- 远程物化视图因网络中断、测试库下线、DB Link 失效而停止刷新,
DBA_REGISTERED_MVIEWS.CAN_USE_LOG仍为'YES',日志持续堆积 - 查卡住的日志:先看
DBA_MVIEW_LOGS.LAST_REFRESH是否长期未更新,再关联DBA_REGISTERED_MVIEWS.SNAPID找出对应 MV - 解除绑定必须用
DBMS_MVIEW.UNREGISTER_MVIEW,参数MVIEW_SITE必须和注册时完全一致(含大小写、域名、端口),否则报ORA-12006 -
PURGE_MVIEW_FROM_LOG后日志表行数减少,但高水位线(HWM)不变——这不是失败,是正常行为;想缩段空间,得先ENABLE ROW MOVEMENT再SHRINK SPACE CASCADE(仅限 ASSM 表空间)











