大批量入库时禁用物化视图刷新,是为了防止MLOG$_xxx日志表爆满、事务锁死及FAST刷新静默降级为COMPLETE,从而避免基表被TM/TX锁长时间阻塞业务DML。
大批量入库时禁用物化视图刷新,不是为了“省资源”,而是避免日志表 mlog$_xxx 被撑爆、事务锁死、刷新退化为 complete 导致基表长时间被 tx 或 tm 锁住——这会直接卡住业务 dml。
为什么批量 INSERT/APPEND 会让物化视图刷新失效
Oracle 11g 的 FAST 刷新依赖物化视图日志中逐行记录的变更向量(CHANGE_VECTOR$$),但以下操作根本不会写日志:
-
INSERT /*+ APPEND */或direct path load:跳过 redo 和触发器,MLOG$_xxx完全不记录 - 分区
EXCHANGE或TRUNCATE + INSERT:若未调用DBMS_MVIEW.PARTITION_CHANGING,日志SNAPTIME$$时间戳会严重滞后 - 批量
UPDATE/DELETE未启用INCLUDING NEW VALUES:新列值或默认值变更不被捕获
结果就是:日志缺失 → DBMS_MVIEW.REFRESH('MV', 'F') 静默 fallback 到 COMPLETE → 全表 DELETE + INSERT → 基表被 TM 锁数分钟甚至小时。
禁用刷新 ≠ 关掉日志,而是停掉消费端
关键动作是暂停刷新调度,而非删日志或关日志。错误做法包括:
-
DROP MATERIALIZED VIEW LOG:清空所有未消费变更,其他复用该日志的 MV 全挂 - 只停 DBMS_JOB 但没清理残留任务:查
SELECT broken, what FROM user_jobs WHERE what LIKE '%refresh%',BROKEN = 'Y'仍会占job_queue_processes - 设
ATOMIC_REFRESH => FALSE后仍高频刷新:频繁TRUNCATE + APPEND会加剧段竞争和 extent 分配延迟
正确做法是:
- 对定时任务:用
DBMS_SCHEDULER.DISABLE('job_name')或DBMS_JOB.BROKEN(job#, TRUE) - 对 ON COMMIT 类型:临时改用
ON DEMAND,执行ALTER MATERIALIZED VIEW mv_name REFRESH ON DEMAND - 确认无活跃刷新会话:
SELECT sid, sql_id FROM v$session WHERE program LIKE '%DBMS_MVIEW%',有则ALTER SYSTEM KILL SESSION
批量入库后如何安全恢复刷新
恢复不是简单跑一次 REFRESH,得先验证日志完整性:
- 查日志最新时间戳:
SELECT MAX(snaptime$$) FROM mlog$_your_table,若比入库结束时间早 >UNDO_RETENTION秒(如 900 秒),后续 FAST 刷新大概率报ORA-01555 - 检查是否还有未消费日志:
SELECT COUNT(*) FROM mlog$_your_table,若远大于入库期间 DML 行数,说明部分变更没被刷走 - 强制全量同步前,先清无效状态:
EXEC DBMS_MVIEW.REFRESH('mv_name', method => 'C', atomic_refresh => FALSE),避免COMPLETE再次锁表
真正容易被忽略的是:批量入库后,即使日志看起来“有数据”,SNAPTIME$$ 若因高并发提交而堆积错乱,FAST 刷新仍会静默失败——必须用 EXPLAIN_MVIEW 查 REFRESH_FAST 的 possible='N' 及对应 msgtxt,而不是靠耗时猜。


















