fast refresh本身不直接写undo,但依赖的变更读取会触发延迟块清除;其undo消耗主源于扫描mlog$_表和源表时的延迟块清除,尤其在日志积压、缺乏索引或on commit刷新模式下显著加剧。

Fast Refresh本身不直接写Undo,但依赖的变更读取会触发延迟块清除
物化视图执行 REFRESH FAST 时,Oracle 并不会在刷新阶段主动产生大量 Undo。真正消耗 Undo 的,是它背后读取变更日志(MLOG$_ 表)和源表基数据的过程——尤其是当这些数据块尚未完成“块级清理”(Block Cleanout)时。
典型触发场景包括:
- 源表或日志表所在表空间启用了
FORCE LOGGING,且大范围扫描MLOG$_XXX表(如积压日志未及时消费) - 源表 DML 频繁但事务提交后未及时触发 cleanout,导致后续 Fast Refresh 的 SELECT 阶段被迫做延迟块清除(Delayed Block Cleanout)
- 物化视图定义含 JOIN 或聚合,刷新时需多次访问基表,放大未清理块的扫描次数
为什么MLOG$_表积压会让Undo暴增?
MLOG$_BIG_TABLE 是普通堆表,默认继承源表的 LOGGING 属性。高频 INSERT 写入它本身不产 Undo,但会产 REDO;而真正吃 Undo 的,是 Fast Refresh 过程中对它的全表扫描 + ROWID 回查 —— 尤其当该日志表缺乏有效索引、或统计信息陈旧时,优化器可能选错执行计划,导致大量逻辑读 + 延迟块清除。
常见表现:
-
V$UNDOSTAT.UNDOBLKS在刷新窗口内突增,但V$TRANSACTION.USED_UBLK显示无长事务 - AWR 报告中 “cleanouts only – consistent read gets” 指标飙升
- 查询
DBA_MVIEW_LOGS发现LAST_REFRESH_DATE滞后数小时以上,说明日志已堆积
ON COMMIT 刷新模式会加剧Undo压力吗?
会,而且非常显著。因为 REFRESH FAST ON COMMIT 要求每次源表事务提交后立即读取刚写入的 MLOG$_ 记录,并立刻应用到物化视图表。这个过程不是后台异步,而是同步嵌入在用户事务上下文中:
- 每个业务事务的提交,都额外绑定了一个 MV 刷新子事务,延长了原事务的 Undo 生命周期
- 若物化视图含聚合或 JOIN,刷新逻辑可能需要多次扫描源表,进一步拉长一致性读所需 Undo 保留时间
- 实测中,开启 ON COMMIT 后,
UNDO_RETENTION实际有效值常被推高 2–3 倍,尤其在高并发小事务场景下
这不是配置错误,而是机制使然:Oracle 必须为整个“源表 DML + 日志写入 + MV 应用”这一连贯动作提供完整的回滚保障。
如何快速定位和缓解?
别先调 UNDO_RETENTION,先确认是不是块清除问题:
- 查是否触发延迟清除:
SELECT name, value FROM v$sysstat WHERE name LIKE '%cleanout%';关注 “cleanouts only – consistent read gets” 是否异常高 - 检查日志表积压:
SELECT COUNT(*) FROM MLOG$_BIG_TABLE;若远超日均 DML 量,说明刷新链路已中断 - 临时缓解:对日志表执行
ALTER TABLE MLOG$_BIG_TABLE NOLOGGING;(仅限紧急),再跑一次DBMS_MVIEW.PURGE_LOG('BIG_TABLE') - 长期方案:将日志表迁出 SYSTEM 表空间,改用独立小 extent 表空间,并定期收集统计信息
最易被忽略的一点:物化视图日志的字段粒度和 INCLUDING NEW VALUES 开关,不仅影响 REDO,也间接决定 Fast Refresh 扫描 MLOG$_ 时的块访问路径和清除频率。少记一列,可能就少扫几千个脏块。











