必须查GV$ACTIVE_SESSION_HISTORY并筛选final_blocking_session非空的记录,结合CURRENT_OBJ#关联DBA_OBJECTS定位具体对象,再按p1raw末两位(06/04)区分行锁或唯一键/ITL问题,最后切至对应实例确认会话状态。

查 GV$ACTIVE_SESSION_HISTORY 而不是 V$ 或 DBA_HIST
单查 V$ACTIVE_SESSION_HISTORY 或 DBA_HIST_ACTIVE_SESS_HISTORY 极大概率漏掉根因,尤其在 RAC 环境下。阻塞源头可能在另一个实例,而 V$ 视图只返回本实例数据,DBA_HIST 又是分钟级聚合、采样稀疏,且默认不含 blocking_instance 字段。
必须用 GV$ACTIVE_SESSION_HISTORY,并显式过滤 blocking_instance IS NOT NULL 或指定 inst_id = &target_inst。否则你看到的只是“中间传递者”,不是真正持锁的那个会话。
- 错误写法:
SELECT * FROM V$ACTIVE_SESSION_HISTORY WHERE event = 'enq: TX - row lock contention' - 正确起点:
SELECT inst_id, session_id, blocking_session, blocking_instance, event, p1raw, sample_time FROM GV$ACTIVE_SESSION_HISTORY WHERE sample_time > SYSDATE - INTERVAL '5' MINUTE AND event = 'enq: TX - row lock contention' AND wait_time = 0 AND blocking_session IS NOT NULL - 时间窗口别写死字符串,用
INTERVAL表达式,避免时区/NLS 影响
识别 final_blocking_session 才算找到根因
blocking_session 字段在 ASH 中常指向“上一级阻塞者”,但那个会话本身可能也被别人卡着。真正在源头持锁、没被任何会话阻塞的,是 final_blocking_session 和 final_blocking_instance 都非空的那条记录——它才是根因。
如果查出某条记录的 final_blocking_session = 0 或为 NULL,基本可断定这就是根阻塞源。90% 场景下,它对应一个未提交事务(如批处理 UPDATE 后忘 COMMIT),或一个执行 DDL 后卡住的会话(如 TRUNCATE 持有 DDL 锁)。
- 查根因必须加字段:
final_blocking_session,final_blocking_instance - 确认该会话是否还活跃:连到
final_blocking_instance对应节点,查V$SESSION中SID = final_blocking_session的STATUS是否为ACTIVE - 若状态是
INACTIVE,但V$TRANSACTION里仍有记录,说明事务残留,需人工判断能否 kill
从 P1RAW 判断是不是真行锁,避免误杀
看到 enq: TX - row lock contention 别急着 kill。先看 p1raw 值末两位:是 '06' 还是 '04',这直接决定问题性质。
p1raw = '54580006'(即 mode=6)表示标准行锁冲突:A 更新某行未提交,B 正等同一行。此时 kill A 或让 A 提交即可解。
p1raw = '54580004'(即 mode=4)则大概率不是行锁,而是唯一键冲突、ITL 不足或索引分裂等待。即使 kill 掉等待者,下一个会话仍会报 ORA-00001 或继续卡住。
- 验证唯一键冲突:查该
sql_id对应语句是否为INSERT INTO ... VALUES (...),且CURRENT_OBJ#指向含唯一索引的表 - 验证 ITL 不足:查表的
PCT_FREE是否过低,或是否存在高并发短事务集中更新同一块 - mode=4 时,优先检查应用逻辑和索引设计,而非直接杀会话
关联 CURRENT_OBJ# 和 OBJECT_NAME 定位具体对象
光知道是 TX 锁不够,得立刻锁定被争抢的是哪张表、哪个索引。ASH 中的 CURRENT_OBJ# 是对象编号,必须关联 DBA_OBJECTS 才能确认真实名称。
尤其注意:物化视图刷新、DDL 操作、甚至审计日志写入都可能表现为对系统表或日志表(如 MLOG$_SALES、AUD$)的锁等待。不查对象名,容易把问题归错方向。
- 关键连接:
GV$ACTIVE_SESSION_HISTORY a JOIN DBA_OBJECTS o ON a.CURRENT_OBJ# = o.OBJECT_ID - 过滤时别只盯表名,也查
o.OWNER IN ('SYS','SYSTEM'),系统对象锁往往更隐蔽 - 若
CURRENT_OBJ# = 0,说明等待不涉及具体用户对象,可能是 undo header、sequence cache 或 library cache 内部结构
根因定位最易被跳过的一步,是查到 final_blocking_session 后,没立刻切到对应实例确认该会话当前状态。ASH 是采样快照,它告诉你“当时谁在持锁”,但那个会话可能已在 2 秒前退出——而你还在原实例上反复查 V$SESSION 等它出现。


















