直接查v$active_session_history抓最近锁等待样本是定位刚发生行锁问题最有效手段,需过滤enq: tx - row lock contention事件、限定时间窗口、关注sql_id/current_obj#/p1raw,并结合v$sql/v$transaction/dba_objects等视图深入分析锁源、持锁事务及热点行。

直接查v$active_session_history抓最近的锁等待样本
ASH采样是定位“刚发生”的行锁问题最有效的手段,比v$session更可靠——因为阻塞可能在你登录前就结束了。v$active_session_history默认每秒采样一次(实际受_ash_sampling_interval控制),保留约1小时(Oracle)或30分钟(OceanBase),所以必须卡准时间窗口。
别用SELECT * FROM v$active_session_history全表扫,容易卡住或权限报错。优先加过滤:
WHERE event = 'enq: TX - row lock contention'-
AND sample_time > SYSDATE - 1/1440(最近1分钟;按需扩大到5或15分钟) -
AND (blocking_session IS NOT NULL OR sid IN (SELECT blocking_session FROM v$active_session_history WHERE ...))——这能同时捞出被堵者和堵人者
关键字段盯紧:sql_id(源头SQL)、current_obj#(对象号,可连dba_objects查表名)、p1raw(锁类型,如54580006表示TX独占锁)。
用sql_id反查执行计划和事务状态
拿到高频出现的sql_id后,不能只看语句文本,得确认它是否真在持锁、持了多久、有没有未提交。
执行以下查询:
SELECT sql_text, executions, elapsed_time/1000000 AS sec, parsing_schema_name FROM v$sql WHERE sql_id = 'your_sql_id';
重点关注:
-
executions = 1但elapsed_time极大 → 很可能是长事务没提交 -
parsing_schema_name非应用用户 → 可能是DBA脚本或ETL任务遗留 - 结合
v$transaction查该SQL关联的事务:SELECT start_time, used_ublk, logon_time FROM v$session s JOIN v$transaction t ON s.taddr = t.addr WHERE s.sql_id = 'xxx'
如果start_time远早于当前时间,且used_ublk > 0,基本坐实是它在持锁。
从current_obj#定位具体表和行级热点
current_obj#是v$active_session_history里最易被忽略的关键线索。它指向被操作的对象(表/索引),不是锁本身,但能快速圈定范围。
执行:
SELECT owner, object_name, object_type FROM dba_objects WHERE object_id = ¤t_obj#;
如果返回的是索引(尤其是唯一索引),要重点检查enq: TX - row lock contention是否由唯一键冲突引发——这时mode=4(非独占)比mode=6更常见,kill会话无用,得查业务是否缺少前置校验。
进一步确认热点行:
- 查
v$session中对应sid的row_wait_obj#、row_wait_file#、row_wait_block#、row_wait_row# - 用
dbms_rowid.rowid_create拼出实际ROWID,再SELECT * FROM <table> WHERE ROWID = '<rid>'验证<p>注意:高并发UPDATE同一数据块时,<code>row_wait_block#可能反复出现,说明ITL槽不足,而非某一行被锁死。生成ASH报告后跳读关键章节,别从头翻
跑
@?/rdbms/admin/ashrpt.sql生成HTML报告后,90%的有效信息集中在两处:-
“Top SQL with Waiting Events”:排序依据是“等待总时长”,不是执行次数。排第一的
sql_id大概率就是根因 -
“Blocking Session Summary”:直接列出阻塞链长度、被堵会话数、平均等待秒数。若显示“1 session blocks 23 others”,不用再猜,就查那个
sid
如果报告里
enq: TX - row lock contention占比超过70%,其他等待事件可以暂时忽略——这是明确信号:问题不在IO或CPU,就在事务逻辑或并发控制上。这时候每个相关sql_id都得点进去看绑定变量值、执行计划里的access_predicates,确认是不是在用非主键条件更新大范围数据。真正容易被绕开的是
p1raw解码和current_obj#反查——不走这一步,你看到的只是“有锁”,不是“锁在哪、谁锁的、为什么锁”。 -
“Top SQL with Waiting Events”:排序依据是“等待总时长”,不是执行次数。排第一的











