ORA-00060在物化视图刷新中本质是锁资源循环等待,非刷新本身失败;需通过v$locked_object等视图定位争用对象与会话,并分析trace文件中的Deadlock graph确认死锁详情及victim会话。
物化视图刷新触发ORA-00060,本质不是“刷新失败”,而是锁资源循环等待
ora-00060在物化视图(mv)刷新场景下,和普通dml死锁逻辑一致:不是mv本身有问题,而是刷新事务与其他会话(可能是业务sql、另一个mv刷新、或etl任务)对同一组行/表/索引持有并等待互斥锁。典型如:mv刷新时执行 update 表a的某几行,而业务线程正持着这些行的锁去更新表b;同时业务线程又在等mv刷新释放表b上的锁——形成闭环。
查清谁和MV刷新在抢同一张表的行锁
重点不是看MV定义,而是看刷新实际执行的SQL和它锁住的对象。立即运行以下查询:
SELECT b.owner, b.object_name, a.session_id, a.locked_mode,
c.machine, c.program, c.status, c.event
FROM v$locked_object a
JOIN dba_objects b ON a.object_id = b.object_id
JOIN v$session c ON a.session_id = c.sid
WHERE b.object_name IN (
SELECT mview_name FROM dba_mviews WHERE owner = 'YOUR_SCHEMA'
)
ORDER BY b.object_name;关键点:
-
locked_mode = 6表示排他锁(X),重点关注这类行; -
program字段若显示oracle@... (J000)是后台作业(如DBMS_MVIEW.REFRESH调用),若显示jdbc thin client或具体应用名,则是业务会话; - 如果多个
session_id同时锁住同一object_name的不同行,且event是enq: TX - row lock contention,基本可确认冲突源。
避免MV刷新与业务DML交叉锁的实操原则
物化视图刷新本身无法跳过锁,但可以大幅降低冲突概率:
- 强制使用
ATOMIC_REFRESH => FALSE:避免刷新全程锁整张基表,改用TRUNCATE+INSERT,减少锁持有时间; - 刷新前检查业务低峰期:避开
UPDATE/DELETE高频时段,尤其避免在定时批处理窗口内刷新; - 确保基表关键WHERE字段有高效索引:否则MV刷新的
SELECT FOR UPDATE可能升级为全表扫描锁,波及大量无关行; - 不要在MV刷新事务中嵌套调用存储过程或触发远程HTTP——长耗时操作会把锁挂住几十秒,极大增加死锁窗口。
trace文件里Deadlock graph才是唯一真相来源
每次ORA-00060发生,Oracle必写trace文件,路径由 SELECT value FROM v$diag_info WHERE name = 'Diag Trace' 返回。进该目录,找最新生成的以 _ora_ 开头、含 ORA-00060 的文件,打开后直接搜 Deadlock graph 段落。里面会明确列出:
- 两个(或多个)会话的
sid和serial#; - 每个会话正在执行的SQL(含完整
sql_text); - 各自持有的锁(
holding lock)和等待的锁(waiting for)对应哪一行(rowid或file# block#); - 被选为victim的会话ID——这个会话的事务已被回滚,你的应用层必须感知并重试整个业务逻辑,而非只重试MV刷新。
没看trace就动手kill session或加sleep重试,等于蒙眼修车:既可能杀错人,也可能掩盖真正顺序不一致的代码缺陷。


















