ON COMMIT会严重拖慢写操作,ON DEMAND才是生产环境合理默认;ON COMMIT同步阻塞提交、引发高延迟与吞吐下降,仅适用于极少数低吞吐强一致场景;ON DEMAND的FAST刷新需严格满足日志与定义条件,FORCE模式易静默降级为COMPLETE,应显式指定并校验。
on commit 会拖慢所有写操作,on demand 才是生产环境的合理默认选择。 其他说法容易让人误以为“强一致性=必须用 on commit”,实际它只适用于极少数低吞吐、小数据、高一致性的边缘场景。
ON COMMIT 刷新为什么会让 INSERT/UPDATE 变慢
每次基表事务提交(COMMIT)时,Oracle 必须立即执行物化视图的增量更新。这个过程不是“后台悄悄做”,而是同步阻塞主线程,直到变更应用完成。关键开销来自:
- 读取
MATERIALIZED VIEW LOG中对应 ROWID 和变更值(要求日志含INCLUDING NEW VALUES) - 解析并重放 DML 影响(尤其含
GROUP BY或多表JOIN的 MV,需重建中间聚合状态) - 维护 MV 上的索引、触发约束检查、可能引发行级锁等待
压测显示:单次 INSERT 延迟从 2ms 升至 150ms,整体写入吞吐下降 30%–60%。若日志缺失或基表无主键,建 MV 直接报错 ORA-12052,根本无法启用。
ON DEMAND 刷新的“FAST”不是自动生效的
REFRESH FAST ON DEMAND 听起来安全,但“FAST”是否真能跑起来,完全取决于前置条件是否完备:
- 源表必须已建日志,且含
ROWID+ 所有 SELECT 列(例如 MV 里用了TRUNC(sale_date),日志就得包含原始sale_date,不能只记表达式结果) - 聚合 MV 中若含
COUNT(*),日志必须带INCLUDING NEW VALUES,否则UPDATE会被跳过 - 调度脚本中若只写
DBMS_MVIEW.REFRESH('MV_NAME'),默认走FORCE模式——它不报错,但可能静默降级为COMPLETE,一次全量重建就吃光临时表空间
验证方法很简单:DBMS_MVIEW.EXPLAIN_MVIEW('MV_NAME') 查 MSGTXT 字段;刷新前查 DBA_MVIEW_LOGS 确认日志状态;刷新后立刻查 DBA_MVIEW_REFRESH_TIMES 的 LAST_REFRESH_TYPE 是否真为 FAST。
FORCE 刷新模式是隐蔽的性能雷区
REFRESH FORCE 不是兜底方案,而是把问题藏得更深的开关。它在内部按顺序尝试:FAST → COMPLETE,但失败时不抛异常,也不写告警日志。你只能事后翻 V$SESSION_LONGOPS 找 “Refresh materialized view” 耗时超长的记录,或者对比 LAST_REFRESH_DATE 和调度计划是否严重偏移。
更麻烦的是:某次统计信息过期、日志损坏或 MV 定义被意外修改,都可能导致原本稳定的每小时 FAST 刷新,某天突然变成 40 分钟的 COMPLETE,而监控毫无感知。
真正可控的做法是:调度脚本里显式传参 'F'(即 DBMS_MVIEW.REFRESH('MV_NAME', 'F')),并加一层校验——若返回 DBMS_MVIEW.EXPLAIN_MVIEW 显示不支持 FAST,则中止刷新并告警,而不是硬切到 COMPLETE。
最常被忽略的一点:ON COMMIT 的“强一致性”仅对单个 MV 生效,不保证跨多个 MV 的事务可见性顺序;而 ON DEMAND 配合合理调度间隔(如 5 分钟),配合应用层缓存,反而更容易实现端到端可预期的数据新鲜度。一致性不等于实时性,更不等于低延迟写入能力。











