DBMS_MVIEW.REFRESH 不支持异步,始终同步阻塞执行;atomic_refresh=>FALSE是绕过表级锁的核心开关,需确保物化视图真实支持FAST刷新且日志完备,否则会退化为更慢的COMPLETE刷新。
dbms_mview.refresh 本身不支持异步执行,所谓“异步刷新”是常见误解。它总是在调用会话中同步阻塞执行,直到刷新完成或超时。真想规避锁表,得从刷新方式、锁粒度和调度策略入手,而不是寄希望于“后台运行”。
为什么 atomic_refresh => FALSE 是绕过锁表的核心开关
默认 atomic_refresh => TRUE(即不显式传参时)会让 Oracle 先 TRUNCATE 物化视图基表,再 INSERT /*+ append */ 新数据——TRUNCATE 是 DDL,触发 exclusive 表级锁,整个刷新期间业务 DML 完全阻塞。
设为 FALSE 后,Oracle 改用 DELETE + INSERT(非 append),只对变更行加 ROW EXCLUSIVE 锁,读写基本不受影响:
- 前提是物化视图必须真实支持
FAST刷新:查user_mviews.fast_refreshable = 'FAST',不是创建语句里写了REFRESH FAST就算数 - 物化视图日志必须存在且含
SEQUENCE和ROWID:SELECT log_table FROM user_mview_logs WHERE master = 'YOUR_TABLE' - 若日志缺失或字段不全,
atomic_refresh => FALSE会静默退化为COMPLETE,反而更慢更锁
DBMS_SCHEDULER 能“伪异步”,但必须配超时和失败控制
真正能脱离当前会话执行的,只有 DBMS_SCHEDULER。但它不是让刷新变快,而是把阻塞转移到后台 job 进程里——如果没约束,一个卡住的刷新可能拖垮整个调度链。
必须显式配置:
-
max_run_duration => '+000 00:30:00':防 COMPLETE 刷新卡死(LOB 多或统计信息过期时常见) -
max_failures => 1:避免静默重试,失败立即告警 -
job_action中显式传参:DBMS_MVIEW.REFRESH('SCOTT.MV_SALES', method => 'F', atomic_refresh => FALSE),不能依赖默认值
漏掉 max_run_duration 是线上事故高发点,有案例单次刷新 hang 40 分钟导致后续 17 个定时任务堆积。
分区大表刷新别全刷,用 list 参数切片
对按时间分区的物化视图(如 MV_SALES_202604),全量刷新锁表时间与分区数正相关。用 list 参数指定单个分区名,可把锁范围压缩到该分区内部:
EXEC DBMS_MVIEW.REFRESH( list => 'SCOTT.MV_SALES_202604', method => 'F', atomic_refresh => FALSE );
注意点:
-
list必须是完整对象名(OWNER.MVIEW_NAME),只写MV_SALES_202604会报ORA-00942 - 分区名需与物化视图定义中实际使用的分区名严格一致,大小写敏感
- 跨分区关联的 MV 不适用此法,需先确认分区键是否在 SELECT 列表中
锁本身无法消除,但锁的持续时间、影响范围和业务感知程度,全由你控制。最常被忽略的是:不验证 fast_refreshable 状态就硬上 atomic_refresh => FALSE,结果既没避开锁,又因退化为 COMPLETE 刷新拉长了阻塞窗口。


















