refresh fast会静默退化为complete,因oracle不报错但检查失败时自动降级,常见原因包括基表无日志、日志缺sequence或including new values、mv定义含sysdate/分析函数/子查询等不支持元素。

不能只靠 REFRESH FAST ON DEMAND 就让物化视图自动增量更新——必须配日志、配语义、配调度,三者缺一不可。
为什么 REFRESH FAST 会静默退化成 COMPLETE
Oracle 不报错,但查 DBA_MVIEWS.FAST_REFRESHABLE 返回 'NO',说明快速刷新实际未启用。常见原因包括:
- 基表没建日志,或日志缺
INCLUDING NEW VALUES或SEQUENCE() - 物化视图定义含不支持的元素:如
SYSDATE、分析函数、子查询、ROWNUM、跨 DB Link 的表 - 多表连接时,关联列没索引,或连接条件未基于主键/唯一键
- 聚合物化视图缺
COUNT(*),或GROUP BY列未全部出现在SELECT列表中
CREATE MATERIALIZED VIEW LOG 必须带哪些参数
日志是 FAST 刷新的底层支撑,漏一项就无法增量。以基表 sales 为例:
CREATE MATERIALIZED VIEW LOG ON sales WITH PRIMARY KEY, SEQUENCE(amount, sale_date) INCLUDING NEW VALUES;
关键点:
-
PRIMARY KEY或ROWID必选(推荐PRIMARY KEY) -
SEQUENCE()必须包含所有被物化视图引用的列(不只是SELECT列,WHERE 条件里的也要) -
INCLUDING NEW VALUES不可省略,否则 UPDATE 无法捕获新值 - 若基表有多个物化视图共用日志,该日志需满足所有视图的要求(取并集)
如何验证快速刷新是否真在运行
别只看作业是否执行成功,要确认它是否走了增量路径:
- 查
DBA_MVIEW_LOGS看日志是否被消费:LOG_TABLE行数应随刷新下降 - 查
DBA_MVIEWS中LAST_REFRESH_DATE和STALENESS('FRESH'才算成功) - 手动触发一次:
EXEC DBMS_MVIEW.REFRESH('mv_sales', 'F');,再查V$MVREFRESH或跟踪会话,看是否调用了MLOG$_sales - 跨 DB Link 场景下,
REFRESH FAST直接不可用,只能用'C',这点常被忽略
定时调度必须用 DBMS_SCHEDULER,不是 START WITH/NEXT
START WITH SYSDATE NEXT SYSDATE+1 只写进数据字典,不创建任何后台任务。正确做法:
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'job_mv_sales_fast',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN DBMS_MVIEW.REFRESH(''mv_sales'', ''F''); END;',
start_date => TRUNC(SYSDATE)+2/24,
repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0',
enabled => TRUE
);
END;
注意:
- 作业用户必须对基表有
SELECT权限(SELECT ANY TABLE不够) -
job_queue_processes参数建议 ≥ 1000,否则高并发下 job 积压 - 如果用
DBMS_JOB,它在 19c 已弃用,且不支持复杂 repeat_interval
最易被绕过的点:即使日志、定义、调度全对,只要某次刷新失败(比如基表 DML 正在阻塞日志读取),后续刷新可能持续卡在旧 SCN,导致 FAST_REFRESHABLE = 'NO' 却无报错——得定期查 DBA_MVIEW_LOGS.LOG_OWNER 和 DBA_SCHEDULER_JOB_LOG 状态。











