最直接识别当前阻塞关系的方法是查询v$session,关键字段为blocking_session和blocking_instance(rac环境必需),需加status='active'过滤,并结合event判断锁类型;历史阻塞需用dba_hist_active_sess_history按时间窗口与sample_id递减构建阻塞链,ash报告重点关注enq: tx事件及高频sql_id。
查 v$session 快速识别当前阻塞关系
最直接的方式是查 v$session,它能立刻告诉你谁在等、等谁、等了多久。关键字段是 blocking_session 和 blocking_instance(rac 环境必须看这个)。
常见错误是只查 blocking_session IS NOT NULL,却忽略 status = 'ACTIVE' —— 很多阻塞会话已断开但状态未及时清理,导致误判。
- 单实例执行:
SELECT sid, serial#, username, blocking_session, event, seconds_in_wait FROM v$session WHERE blocking_session IS NOT NULL AND status = 'ACTIVE'; - RAC 环境务必加
AND blocking_instance = instance_number或明确指定实例号,否则可能漏掉跨实例阻塞 -
event字段值如果是enq: TX - row lock contention,基本可锁定是行锁冲突,不用再猜
用 dba_hist_active_sess_history 回溯过去几分钟的阻塞链
v$session 只反映“此刻”,而真实故障常发生在 2 分钟前——这时得靠历史 ASH 表。注意:它默认只保留 30 分钟(OceanBase)或 1 小时(Oracle),超时数据自动滚动丢弃,别查太早的时间范围。
容易踩的坑是直接 SELECT * FROM dba_hist_active_sess_history,结果扫全表卡死,还可能因权限不足报错。
- 先缩时间窗口:
WHERE sample_time BETWEEN TIMESTAMP '2026-04-19 05:45:00' AND TIMESTAMP '2026-04-19 05:48:00'(务必用数据库所在时区) - 聚焦阻塞源头:用
CONNECT BY构建阻塞链,但必须加条件sample_id = PRIOR sample_id - 1(不是相等),否则会把不同时刻的会话强行连起来 - 查出的
blocking_session如果为 0 或空,说明它是根阻塞者;若反复出现同一sql_id,优先检查它的执行计划和事务是否未提交
ASH 报告里重点盯 enq: TX - row lock contention 和 sql_id
生成 ASH 报告(@?/rdbms/admin/ashrpt.sql)后,别从头翻。直接跳到 “Top SQL with Waiting Events” 和 “Blocking Session Summary” 两节。
如果 enq: TX - row lock contention 占比超过 70%,基本不用看别的——就是行锁争用。这时候报告里每个相关 sql_id 都要点进去,看它操作的是哪张表、什么条件、有没有 FOR UPDATE 或未提交的 UPDATE/DELETE。
- 高频出现的
sql_id对应的 SQL,用SELECT * FROM v$sql WHERE sql_id = 'xxx'查executions和elapsed_time,判断是偶发还是持续压测引发 - 如果该 SQL 的
current_obj#指向一张小表,且等待事件是db file sequential read,说明可能索引失效,正在全表扫找被锁的行 - 注意绑定变量窥探(bind peeking)影响:同一
sql_id下不同child_number可能对应完全不同执行路径,得分开看
别依赖采样精度,但要对齐时间与实例维度
ASH 是概率采样,每秒一次,不是录像。你不可能还原第 127.345 秒发生了什么,但能确认 “127–129 秒之间有 8 个会话同时卡在 enq: TX 上”,这就够定位问题窗口了。
最容易被忽略的是时区和实例对齐。比如你在应用日志里看到报错时间是 UTC+8 的 17:22:18,但数据库时区设的是 UTC,那查询 ASH 时就得用 TIMESTAMP '2026-04-19 09:22:18',否则直接查不到数据。
- RAC 环境下,
blocking_instance和instance_number必须成对使用,单独查某个实例的v$session会漏掉跨节点阻塞 - 如果查
dba_hist_active_sess_history返回空,先确认DBA_HIST_ACTIVE_SESS_HISTORY视图是否存在、是否有 SELECT 权限,而不是立刻怀疑采集没开(它默认开启) - 临时性抖动(sample_time 密集区域和共现的
sql_id











