Oracle 12c 不支持真正的异步刷新机制,DBMS_MVIEW.REFRESH 本身同步执行,“异步”仅能通过 DBMS_SCHEDULER 创建后台作业实现,但刷新逻辑仍为阻塞式、事务级,需显式配置 job_action、refresh_method 和 atomic_refresh 等参数以避免失败或性能雪崩。
oracle 12c 不支持真正的异步刷新机制——dbms_mview.refresh 本身是同步执行的,所谓“异步”只能靠外部调度器(如 dbms_scheduler)把刷新操作扔进后台作业运行,但刷新逻辑仍是阻塞式、事务级的。
DBMS_SCHEDULER 创建刷新作业才是 12c 的“异步”实质
12c 没有 REFRESH_ALL_MVIEWS(该函数从 19.11 才引入),也没有 ON DEMAND 的自动排队能力。你必须显式创建一个调度作业,让它在后台调用 DBMS_MVIEW.REFRESH:
- 不能直接写
DBMS_MVIEW.REFRESH('MV_NAME', 'F')并期望它“自动异步”,那只是当前会话卡住等结果 - 正确做法是用
DBMS_SCHEDULER.CREATE_JOB,把刷新包装成PL/SQL_BLOCK类型作业,例如:BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'refresh_mv_sales_job', job_type => 'PL/SQL_BLOCK', job_action => 'BEGIN DBMS_MVIEW.REFRESH(''DW.SALES_MV'', ''F''); END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0', enabled => TRUE ); END; - 注意
job_action中的物化视图名必须带 schema,且整个字符串用单引号包裹;内层再套单引号需转义为两个单引号 - 该作业默认以创建者身份运行,若刷新跨 schema,需提前授予
REFRESH ANY MATERIALIZED VIEW权限
为什么作业跑起来还是卡住或失败?常见硬坑
即使作业建成功,实际运行时仍可能 hang 住、报错或静默跳过,核心原因不是调度问题,而是刷新参数和环境没对齐:
-
method => 'F'却没建物化视图日志 → 报ORA-12034;查USER_MVIEW_LOGS确认基表是否有对应日志 - 日志存在但
SNAPTIME$$ = DATE '4000-01-01'→ 说明基表 DML 没提交,或用了/*+ APPEND */跳过触发器,日志根本没写入 - 作业里没显式指定
refresh_method→ 默认走物化视图定义里的刷新类型(可能是ON COMMIT,但在作业里不生效),务必写死'F'或'C' - 忘记设
ATOMIC_REFRESH => FALSE→ 大 MV 刷新时占用大量 undo,作业可能因ORA-01555或超时中断;加这个参数后可分段提交,但刷新中查询可能看到空或中间态
如何验证作业真刷了,而不是“假装成功”
调度作业返回 “Job created” 不代表数据更新了。必须查底层状态,因为 FAST 刷新可能静默跳过、COMPLETE 可能锁表导致查询仍读旧快照:
- 查
DBA_MVIEW_REFRESH_TIMES:确认LAST_REFRESH_DATE和LAST_REFRESH_TYPE是否更新,且值是F或C,不是?(FORCE) - 查
USER_MVIEW_LOGS.LAST_PURGE_DATE:如果FAST刷新成功,这个字段时间会推进;没变=日志根本没被消费 - 不要只 SELECT 物化视图看数据——若
ATOMIC_REFRESH => TRUE,刷新期间查询会被阻塞或看到旧版本;改用SELECT COUNT(*) FROM MV_NAME AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' MINUTE)对比 - 监控
V$SESSION_LONGOPS,过滤opname LIKE '%Refresh%',看是否真在跑、耗时是否异常
12c 的“异步刷新”本质是把同步操作移到后台线程执行,它不改变刷新本身的锁行为、undo 消耗或日志依赖。最容易被忽略的是:你以为作业在后台跑就安全了,其实它照样会锁基表、争用临时表空间、甚至拖垮 RAC 集群——尤其当多个作业同时刷有依赖关系的 MV 时,顺序错乱或锁等待会直接引发雪崩。


















