物化视图卡在refreshing状态需立即查v$session和v$locked_object定位阻塞会话与锁对象,根本原因是atomic_refresh=true导致事务级锁、undo膨胀及行锁冲突;应显式设atomic_refresh=>false启用truncate+insert,并验证日志完整性与mv编译态。

物化视图卡在 REFRESHING 状态,不是“正在运行”,而是事务或会话已阻塞——必须立刻查锁和会话,而不是等超时或翻 USER_MVIEW_ANALYSIS。
查 v$session 和 v$locked_object 定位阻塞源头
REFRESHING 卡住的第一信号是会话挂起,而非时间久。直接查活跃会话和锁表对象,比猜原因快得多:
- 运行
SELECT sid, serial#, sql_id, event, state, seconds_in_wait FROM v$session WHERE status = 'ACTIVE' AND program LIKE '%DBMS_MVIEW%',确认是否真在执行(event为db file sequential read或enq: TX - row lock contention就是卡点) - 若发现
sql_id为空或event长期为SQL*Net message from client,大概率是客户端断连但服务端事务未清理,需人工ALTER SYSTEM KILL SESSION - 查锁对象:
SELECT object_name, locked_mode FROM v$locked_object lo JOIN dba_objects ao ON lo.object_id = ao.object_id,重点看基表、MLOG$_xxx日志表、物化视图本身是否被锁
atomic_refresh=TRUE 是卡死高频原因
默认 atomic_refresh => TRUE 强制整个刷新在一个事务里完成:DELETE → INSERT → COMMIT。百万级数据下极易撑爆 undo、触发 ORA-01555,或因行锁反向阻塞自己。
- 手动刷新必须显式传参:
DBMS_MVIEW.REFRESH('MV_SALES', atomic_refresh => FALSE),改用 TRUNCATE + INSERT 模式,跳过 redo/undo,锁粒度降到表级且只在 TRUNCATE 瞬间 - 定时任务(
DBMS_JOB或DBMS_SCHEDULER)中不能依赖默认值,必须在封装过程里硬编码该参数 - 副作用是刷新过程中物化视图短暂为空,应用层需能容忍;若不能,得换分区交换方案,而非强行保“始终有数据”
查 DBA_JOBS 或 DBA_SCHEDULER_JOBS 确认作业状态
自动刷新失效,90% 是调度机制没跑起来,不是物化视图定义问题:
- 查
DBA_JOBS:SELECT job, what, broken, last_date, next_date FROM DBA_JOBS WHERE what LIKE '%DBMS_MVIEW.REFRESH%',若broken = 'Y'或next_date = DATE '4000-01-01',说明任务已被 Oracle 自动禁用 - Oracle 12c+ 推荐用
DBA_SCHEDULER_JOBS替代:SELECT job_name, state, last_start_date, running_instance FROM dba_scheduler_jobs WHERE job_action LIKE '%REFRESH%' -
job_queue_processes必须 > 0,且要确认数据库未处于RESTRICTED SESSION状态(SELECT logins FROM v$instance返回RESTRICTED时所有 job 静默停摆)
别信 LAST_REFRESH_ERROR,盯住 10046 trace 和 alert 日志
USER_MVIEWS.LAST_REFRESH_ERROR 只存最近一次错误,常被覆盖;真正报错堆栈藏在 session trace 和 alert 日志里:
- 刷新前开 trace:
ALTER SESSION SET EVENTS '10046 trace name context forever, level 12',再执行DBMS_MVIEW.REFRESH - 从生成的 trace 文件里找真实报错堆栈,比如
ORA-01555后面是否跟着snapshot too old,或ORA-12004是否源于日志缺失列 - 同步检查
alert.log,尤其关注刷新时段是否有ORA-00600、ORA-07445等内部错误,这类问题不会写进LAST_REFRESH_ERROR
最易被忽略的是:REFRESHING 状态本身不提供进度信息,它只表示“事务没提交”,而这个事务可能卡在元数据检查、日志读取、甚至远程 DBLink 响应上——所以必须结合 v$session 的 sql_id 和 v$session_longops 的 opname 双向交叉验证,才能定位到真实卡点。











