物化视图刷新卡住且v$locked_object显示锁表时,应先定位锁源会话并评估是否可中止,再将DBMS_MVIEW.REFRESH的ATOMIC_REFRESH设为FALSE以降低锁争用,同时检查MV状态是否为NEEDS_COMPILE或UNUSABLE并针对性修复。
物化视图刷新卡住,v$locked_object 显示锁表了怎么办
物化视图刷新(尤其是 fast 刷新)本质是一组 dml 操作,会争抢基表或物化视图日志(materialized view log)的行锁或表锁。当源表正被大量写入(比如批量导入、大事务更新),而物化视图又在同时刷新,极易触发死锁或长时间阻塞。
典型现象是:SELECT * FROM user_mviews 查到 STALENESS = 'STALE',但手动执行 DBMS_MVIEW.REFRESH 一直不返回;查 v$locked_object 发现物化视图基表或日志表被锁住,且持有者会话状态为 ACTIVE 或 INACTIVE 但 this_date 长时间未更新。
- 先确认是否真被锁:运行
SELECT object_name, locked_mode FROM v$locked_object lo, dba_objects ao WHERE lo.object_id = ao.object_id,重点看基表名、物化视图日志表(如MLOG$_MEMBER_ORDER) - 别急着
ALTER SYSTEM KILL SESSION—— 先查锁来源:SELECT sid, serial#, sql_id, event FROM v$session WHERE sid IN (SELECT session_id FROM v$locked_object) - 若锁定会话正在跑一个长存储过程(哪怕它不碰物化视图相关表),也极可能是它间接占用了 undo 或回滚段资源,导致刷新事务无法推进;优先中止该过程再试
DBMS_MVIEW.REFRESH 的 ATOMIC_REFRESH 参数为什么必须关
默认 ATOMIC_REFRESH => TRUE 表示刷新全程在一个事务里完成:先删旧数据,再插新数据,全程加锁、写 redo/undo。对百万级以上数据,这不仅容易锁表,还会撑爆 undo 表空间(有案例回退文件涨到 30GB),最终触发 ORA-01555 或直接 hang 住。
设为 FALSE 后,Oracle 改用「先截断(TRUNCATE)再插入」方式,跳过事务日志记录,大幅降低锁粒度和资源消耗,是生产环境高并发刷新的刚需配置。
- 手动刷新时显式指定:
DBMS_MVIEW.REFRESH('MV_SPMEMBERORDER', atomic_refresh => FALSE) - 定时任务(
DBMS_JOB或DBMS_SCHEDULER)中,需确保调用封装过程时传入该参数,不能依赖默认值 - 注意副作用:设为
FALSE后,刷新过程中物化视图会短暂为空(非空闲状态),应用层需容忍这个窗口期;若业务强依赖“始终有数据”,需配合应用侧双读逻辑或使用分区交换方案
为什么 FAST 刷新突然变慢甚至失败,却查不到明显锁
表面无锁,但刷新仍卡死,常见于跨库场景(比如通过 DBLink 从 Oracle 10g 拉 SQL Server 数据)或物化视图定义含隐式约束冲突。此时问题不在锁,而在事务隔离与数据一致性校验环节。
例如:SQL Server 源表字段 ChargeEmp 历史允许 NULL,但物化视图建模时 Oracle 自动推导出 NOT NULL 约束,刷新时遇到 NULL 值就报 ORA-01400;又或者 DBLink 连接超时、远端数据库版本太低(如 10.2.0.5),不支持某些增量刷新协议,导致刷新进程挂起在等待远端响应上。
- 查错误日志:
SELECT * FROM user_jobs WHERE what LIKE '%REFRESH%'找对应 job_id,再查dba_jobs_running和dba_scheduler_job_log(推荐迁移到DBMS_SCHEDULER,有完整日志) - 验证 DBLink 可用性:
SELECT * FROM dual@remote_db;检查远端表结构变更(如新增 NOT NULL 字段但无默认值) - 临时绕过约束:在 SELECT 子句中用
NVL("ChargeEmp", 'N/A')显式补缺,避免 Oracle 推导出非空约束
物化视图状态为 NEEDS_COMPILE 或 UNUSABLE 时,刷新必然失败
这两种状态常被忽略,但它们会让任何刷新操作静默失败或报错 ORA-12008: error in materialized view refresh path。根本原因不是锁,而是元数据已失效:比如基表上的视图被重建、DBLink 被删后重建、甚至远端对象权限被回收。
NEEDS_COMPILE 是编译态问题,UNUSABLE 是数据态损坏(比如刷新中途被 kill 导致物化视图处于中间态),两者都必须人工干预,自动刷新不会修复。
- 查状态:
SELECT mview_name, staleness, compile_state FROM user_mviews - 编译修复:
ALTER MATERIALIZED VIEW MV_NAME COMPILE(仅对NEEDS_COMPILE有效) - 重建修复:
ALTER MATERIALIZED VIEW MV_NAME REBUILD或干脆DROP+CREATE(对UNUSABLE更可靠,但大数据量耗时久) - 特别注意:
REBUILD不重置刷新时间,NEXT_DATE仍按原计划走;若想立即刷新,需额外执行一次DBMS_MVIEW.REFRESH
真正麻烦的是那些依赖 DBLink 的物化视图——状态可能显示 UNDEFINED,这时 STALENESS 字段本身不可信,必须结合远端数据变更时间、DBLink 连通性、以及本地日志综合判断,不能只看一个字段。

















