atomic_refresh=true时物化视图锁表并事务内delete+insert,导致查询不可用;false时启用out-of-place刷新,需显式rowid/主键、禁on commit、预留temp空间。

ATOMIC_REFRESH=TRUE 时物化视图会锁表、清空再重插
默认行为是 ATOMIC_REFRESH=TRUE,整个刷新在一个事务里完成:先 DELETE 所有行,再 INSERT 新数据。这期间查询会看到空结果或被阻塞,不是“慢”,而是真实不可用。
适合场景:对一致性要求极高、能接受短时不可用、且刷新量不大(比如几万行以内);或者物化视图本身不被高频查询依赖。
- 必须保证 UNDO 表空间足够大——
DELETE+INSERT会产生大量 UNDO 记录 - 无法用于 ON COMMIT 刷新模式的物化视图(Oracle 直接拒绝调用)
- 如果刷新中途失败,整个事务回滚,视图数据不变,但耗时可能很长
ATOMIC_REFRESH=FALSE 启用 Out-of-Place 刷新,查询不中断
设为 FALSE 后,Oracle 会新建一个临时物化视图(类似 MV_NAME_SNAP_XXXX),刷完再原子切换指针。原视图始终可查,返回的是旧快照,新数据“悄无声息”就位。
但这个“优雅”是有硬门槛的:
- 物化视图定义中必须显式包含基表的
ROWID或主键列,否则报ORA-32313 - 不能含
DISTINCT、表达式列、嵌套视图,否则 Oracle 认为无法保证行级映射 - 禁止搭配
ON COMMIT模式,否则调用DBMS_MVIEW.REFRESH时直接报错 - 临时段空间压力翻倍——同时存两份数据,需提前检查
TEMP表空间剩余容量
COMPLETE 刷新下 atomic_refresh 参数影响极大
完全刷新走 method => 'C' 时,ATOMIC_REFRESH 决定底层执行路径:
-
TRUE→DELETE + INSERT,走常规 DML,占用 UNDO,慢且易失败 -
FALSE→TRUNCATE + INSERT /*+ APPEND */,绕过 UNDO,写入极快,REDO 也少得多
尤其在大表刷新(比如上亿行)且 UNDO 空间紧张时,ATOMIC_REFRESH=FALSE 几乎是唯一可行选项。但注意:TRUNCATE 是 DDL,会隐式提交,所以它天然是非原子的——单个 MV 刷新失败不影响其他。
FORCE 刷新时 atomic_refresh 的行为容易被忽略
method => 'F'(FAST)或 '?'(FORCE)时,ATOMIC_REFRESH 仍生效,但作用逻辑不同:
- FAST 刷新本身是增量操作,
ATOMIC_REFRESH=TRUE仅控制是否把所有增量变更包进一个事务 - FORCE 刷新先尝试 FAST,失败才 fallback 到 COMPLETE —— 此时 COMPLETE 部分的行为仍由
ATOMIC_REFRESH决定 - 也就是说,
method => '?', atomic_refresh => FALSE可能先做非原子的快速刷新,再在 fallback 时做非原子的完全刷新
真正容易踩坑的是:以为设了 atomic_refresh => FALSE 就万事大吉,却忘了 FAST 刷新本身依赖物化视图日志。日志缺失时 FORCE 会 fallback,但 fallback 后的 COMPLETE 是否能用非原子方式,取决于你有没有显式传参——没传就用默认 TRUE,照样卡死。











