物化视图刷新产生大量redo的主因是默认atomic_refresh=true触发高开销临时表路径、lob列强制物理复制、undo全量刷盘及日志表未设nologging;解决需设atomic_refresh=>false、nologging、确保fast刷新条件并清理mlog$僵尸数据。

直接说结论:物化视图刷新产生大量 REDO,不是因为“刷新动作本身必须写日志”,而是因为默认配置(ATOMIC_REFRESH=TRUE、未设 NOLOGGING、含 LOB 列、日志结构不当)把本可跳过的物理写入全塞进了重做流。
ATOMIC_REFRESH=TRUE 强制走临时表路径,LOB 和 UNDO 全量刷盘
ATOMIC_REFRESH=TRUE 是默认值,但它在 COMPLETE 刷新时会触发一套高开销路径:
- Oracle 不直接
TRUNCATE+INSERT /<em>+ APPEND </em>/,而是建临时表 → 全量插入 → 原子替换 - 所有基表中定义的
CLOB/BLOB列,哪怕 MV 查询里没 SELECT,只要列存在且被包含在 MV 结构中,就会强制走物理复制,每字节都进 REDO - 全量数据写入 UNDO 段,极易触发
ORA-01555,同时放大 REDO size -
TRUNCATE本身不写 REDO,但该模式下根本不会执行 TRUNCATE,而是 DELETE + INSERT,REDOLOG 爆涨
解决办法:
- 显式传参
atomic_refresh => FALSE(前提是 MV 定义不含聚合、连接、DISTINCT) - 配合
parallelism => 4或8加速直写,避免 PGA 争用
物化视图表或日志表没设 NOLOGGING,变更全记重做
NOLOGGING 不是“不记录任何日志”,而是跳过 REDO 记录(仍写 UNDO,仍受约束检查),对批量写入极有效:
- 创建 MV 时加
NOCACHE NOLOGGING:CREATE MATERIALIZED VIEW mv_sales NOLOGGING CACHE AS SELECT ...
- 日志表
MLOG$_xxx默认是 LOGGING,需单独改:ALTER TABLE MLOG$_SALES NOLOGGING;
- 注意:
NOLOGGING后首次备份前,该段不可恢复;主备库场景下,备库可能丢失这部分数据
常见误操作:
- 只给 MV 表设了
NOLOGGING,但忘了日志表 - 在归档模式下盲目设
NOLOGGING,又没及时做备份,导致恢复链断裂
FAST 刷新失败降级为 COMPLETE,重复写日志
FAST 刷新一旦失败,Oracle 自动 fallback 到 COMPLETE,而你可能完全没察觉:
- 常见诱因:
INCLUDING NEW VALUES日志缺ROWID或SEQUENCE - 分区表基表的日志没包含分区键(如
trans_date),导致无法分区裁剪,扫描全量日志再过滤,逻辑读暴涨,间接推高 REDO - 日志表堆积“僵尸数据”:
SELECT MIN(snaptime$$) FROM MLOG$_xxx返回远古时间戳(如 2025-01-01),说明某个 MV 卡住未消费,旧日志一直挂着,每次 FAST 刷新都得扫一遍,结果还是降级
验证方式:
- 查日志定义:
SELECT log_table, rowids, sequence, primary_key FROM user_mview_logs WHERE log_table = 'MLOG$_SALES'; - 确保
rowids = 'YES'且sequence = 'YES',字段列表含分区键
并行刷新没控资源,多个会话抢着写 REDO
parallelism > 1 本身不增加 REDO 总量,但会集中释放压力,暴露底层瓶颈:
- 并行进程共用同一组 REDO 日志,LGWR 成为热点,
log file parallel write等待上升 - 若
PARALLEL_MAX_SERVERS设置过高,或空闲区碎片多,INSERT /<em>+ APPEND </em>/频繁等待新区分配,实际变成串行写,REDOSIZE 却已按并行规模累积 - 含
SECUREFILE LOB时,并行加载自动启用,但要求所有 LOB 段CHUNK大小一致(查USER_LOBS.chunk),否则部分 LOB 写空,后续补数据又触发二次 REDO
建议:
- 实测
parallelism = 4或8最稳,超过后收益递减 - 刷新前确认:
SELECT tablespace_name, SUM(bytes)/1024/1024 MB FROM dba_free_space GROUP BY tablespace_name ORDER BY MB DESC;,确保目标表空间有连续大块空闲
真正难处理的,是那些“看起来没改什么,却每天涨几百MB 归档”的场景——往往卡在日志表的 snaptime$$ 滞留和分区键遗漏上,查不到 SQL,也看不到大事务,只能从 MLOG$ 底层结构一层层往下挖。











