不能用 connect by 拼阻塞链,因为 ash 中 blocking_session 是瞬时采样值,非持续关系;真实链路需基于 sample_id 递减、同一会话连续 waiting 状态及 final_blocking_session 穿透定位。

别用 CONNECT BY 拼阻塞链,ASH 里没有“静态关系”,只有每秒快照;真实链路必须靠 SAMPLE_ID 递减、同一会话连续行为+final_blocking_session 穿透定位。
为什么不能用 CONNECT BY PRIOR blocking_session = session_id
ASH 是滚动内存表,SAMPLE_ID 严格递增、每秒一条。用 CONNECT BY 强行关联不同时间点的 blocking_session,等于把上午 9:45 的会话 A 和下午 3:20 的会话 B 错误连成父子——它们根本没同时存在过。常见错误是查出 A→B→C 链后 kill B,结果 C 还在等 A 持有的锁,问题没解。
-
blocking_session是采样瞬间值,不是持续状态;两次采样之间持锁会话可能已提交/断连 -
CONNECT BY不加SAMPLE_ID时序约束,本质是在拼凑伪链 - 真正有效的链路必须满足:同一会话在连续几个
SAMPLE_ID(如 10001→10002→10003)中始终处于session_state = 'WAITING'且event相同
怎么用 SAMPLE_ID 递减追踪真实等待路径
阻塞不是“关系”,而是“时间序列上的等待延续”。关键不是谁指向谁,而是某个会话在连续几秒内是否卡在同一事件上,并逐步出现 blocking_session 或 final_blocking_session 值。
- 先锁定目标等待:查最近 5 分钟内
event = 'enq: TX - row lock contention'且session_state = 'WAITING' - 按
session_id+SAMPLE_ID降序排列,看同一session_id是否在连续SAMPLE_ID(如差值为 1)中反复出现 - 若该会话在
SAMPLE_ID = 10005时blocking_session IS NULL,但在10006时变为 456,说明它刚被阻塞——此时才开始追踪 456 - 不要 JOIN 多个会话,要分步查:先盯住一个等待会话的连续样本,再单独查
final_blocking_session对应会话的实时状态
为什么 final_blocking_session 比 blocking_session 更可靠
final_blocking_session 是 Oracle 12c+ 引入的穿透字段,它跳过中间层(A→B→C),直接指向源头持锁者。而 blocking_session 在 ASH 中漏报率高——锁持有短于 1 秒、或刚好在采样间隙提交,它就为空。
-
blocking_session为空 ≠ 没阻塞,大概率是漏采,或根本是library cache lock伪装成 TX 等待 - RAC 环境下,
blocking_session可能只指向本节点中间会话,真正持锁者在另一实例上;必须配合final_blocking_instance校验 - 查到非空
final_blocking_session后,立刻去v$session查该sid实时状态:SELECT sid, serial#, username, status, event, sql_id FROM v$session WHERE sid = <value></value> - 若查不到,说明它已提交/回滚/断连,这时要转向
dba_hist_active_sess_history或结合v$transaction看长事务
RAC 下必须校验 final_blocking_instance 才算落地
跨节点阻塞不会出现在本地 v$session 里。只查 final_blocking_session 不看 final_blocking_instance,等于在错的实例上找人。
- 拿到
final_blocking_session = 123和final_blocking_instance = 2后,先确认该实例是否存在:SELECT instance_number FROM v$instance - 若当前是实例 1,但
final_blocking_instance = 2,就得连到实例 2 上执行v$session查询 - 别用
GV$ACTIVE_SESSION_HISTORY替代——它只是各节点V$视图的 UNION ALL,不解决跨实例定位问题 - 如果
final_blocking_session = 0或为空,说明它是根阻塞源,大概率就是那个没提交的批处理会话
最易被忽略的点:所有 ASH 查询必须带时间窗和 session_state = 'WAITING' 双过滤,否则结果混入 CPU 运行中或空闲会话,链路判断全错;另外,final_blocking_session 只在 ASH 里存在,且必须配合 SAMPLE_TIME 过滤才可信——离散的单条记录没意义,得看它在连续秒级样本中的稳定性。











