FAST REFRESH 必须配合完整物化视图日志,否则Oracle静默降级为COMPLETE REFRESH;需确保WITH PRIMARY KEY、INCLUDING NEW VALUES、SEQUENCE齐全,且日志字段覆盖所有相关列。

FAST REFRESH 必须配全 MATERIALIZED VIEW LOG
不建日志,或者日志字段漏项,FAST REFRESH 就是空谈——Oracle 会静默降级为 COMPLETE REFRESH,I/O 翻倍还锁表。常见错误包括:WITH PRIMARY KEY 没加、INCLUDING NEW VALUES 忘写、聚合列没进 SEQUENCE 列表。
实操建议:
- 基表无主键?改用
WITH ROWID,但确认不是 IOT 表或临时表 - 物化视图含
COUNT(*)或SUM(amt)?日志必须带SEQUENCE和INCLUDING NEW VALUES - 查日志是否就位:
SELECT ROWIDS, PRIMARY_KEY, SEQUENCE FROM user_mview_logs WHERE master = 'YOUR_TABLE',三个字段都得是 YES - 日志字段要覆盖所有 SELECT 列、GROUP BY 列、WHERE 条件列,少一个,
FAST就失效
ATOMIC_REFRESH => FALSE 不是开关,是条件触发器
ATOMIC_REFRESH => TRUE(默认)等于把整个刷新塞进单事务:DELETE → INSERT → COMMIT。百万级 MV 下,undo 膨胀、redo 写满、行锁堆积,业务 DML 一碰就卡。设成 FALSE 确实能解,但只在三件事全满足时才真正生效。
实操建议:
- 先确认支持 FAST:
SELECT fast_refreshable FROM user_mviews WHERE mview_name = 'YOUR_MV'返回必须是FAST,不能是DIRLOADDML或UNDEFINED - 日志结构完整:
ROWIDS和SEQUENCE都为 YES - 调用时必须显式传参:
DBMS_MVIEW.REFRESH('MV_NAME', 'F', atomic_refresh => FALSE)—— 封装在 JOB 或存储过程里也得硬编码,不能靠默认值 - 验证是否真生效:查
v$transaction应看到多个事务地址;执行计划里应出现TRUNCATE TABLE或带/*+ APPEND */的分批 INSERT
ON DEMAND + 显式指定 'F',别信 FORCE
REFRESH FORCE 听起来省心,实际是隐患放大器:一次日志损坏、一条统计信息过期,就会让本该秒级完成的 FAST 刷成全表扫描的 COMPLETE,CPU、IO、临时表空间全爆。更糟的是,它不报错,只悄悄降级。
实操建议:
- 调度脚本里永远写死
'F':DBMS_MVIEW.REFRESH('MV_NAME', 'F'),别用'?'或默认参数 - 加前置校验逻辑:运行前查
DBA_MVIEW_LOGS中日志表行数是否持续增长,查user_mviews的staleness是否为FRESH - 避免
ON COMMIT:除非基表极小(日增不到百行)、且业务能接受写入延迟跳到数百毫秒,否则它会让主库吞吐量掉 30%–60% - 定时任务避开业务高峰,用
parallelism => 2控并发,别盲目设高
刷新频率不是越密越好,5 分钟往往是反向指标
Oracle 11g 下高频刷新(如每 5 分钟)极易拖垮系统,根本原因不在“要不要快”,而在底层扛不住:MLOG$_xxx 缺复合索引导致 DML 堆积、每次 FAST 都要解析 CHANGE_VECTOR$$、job_queue_processes 不足引发排队、ATOMIC_REFRESH => FALSE 频繁 TRUNCATE 加剧段竞争。
实操建议:
- 报表类场景(BI、驾驶舱):接受 15–60 分钟延迟,设为
NEXT SYSDATE + INTERVAL '15' MINUTE - 查基表变更节奏:若 DML 高峰在夜间 batch,就把刷新统一挪到凌晨 2 点后集中执行
- 必须检查三项硬约束:
SEQUENCE和ROWID日志已启用、刷新作业已迁至DBMS_SCHEDULER(别用废弃的DBMS_JOB)、基表分区且日志加了PCT - 哪怕设成每秒刷一次,只要缺上述任一条件,Oracle 就只会走
COMPLETE,还不报错
最常被忽略的点是:物化视图日志的 PCT 支持和分区交换后的 DBMS_MVIEW.PARTITION_CHANGING 调用——这两个动作不补上,FAST 刷新就是纸面功能。


















