查v$active_session_history必须加时间窗和等待状态过滤,仅查最近3–5分钟且session_state='waiting'、event为'enq: tx%'或'library cache lock',漏掉session_state='waiting'会混入cpu/空闲会话干扰判断。

查 v$active_session_history 必须加时间窗和等待状态过滤
不加条件直接查 v$active_session_history 会扫全内存缓冲区(默认约1小时),轻则卡住、重则权限报错。生产环境必须缩窄范围:只查最近3–5分钟,且只取真正“卡着”的会话。
关键条件就三个:SAMPLE_TIME > SYSDATE - 5/1440(5分钟)、session_state = 'WAITING'、event LIKE 'enq: TX%' 或 event = 'library cache lock'。漏掉 session_state = 'WAITING',结果里会混入 CPU 运行中或空闲会话,干扰判断。
- 别用
SELECT * FROM v$active_session_history——这是最常见也最危险的起点 -
enq: TX - row lock contention表示行锁争用,大概率是事务未提交或FOR UPDATE没释放 -
enq: TM - contention是表级锁,常见于 DDL 执行中(如ALTER TABLE) -
library cache lock多半是硬解析风暴,不是数据锁,排查方向完全不同
优先用 final_blocking_session 而不是 blocking_session
blocking_session 在 ASH 里只是采样瞬间快照,持锁时间短于1秒、或刚好在两次采样之间提交/回滚,它就为空。你看到大量 enq: TX% 等待但 blocking_session IS NULL,不等于没阻塞——更可能是漏采,或根本是 library cache lock 伪装成 TX 等待。
final_blocking_session(Oracle 12c+)能穿透 A→B→C 级联链,比 blocking_session 更稳。若它非空,立刻去 v$session 查该 SID 当前状态——v$session 是实时的,v$active_session_history 是快照,两者不能 JOIN,只能人工串。
- RAC 环境下必须同时看
final_blocking_instance,跨节点阻塞不会出现在本地v$session里 - 如果
final_blocking_session是 0 或空,说明它是根阻塞源,不是被别人阻塞的 - 查到 A → B → C 链后 kill B,C 很可能还在等 A 持有的锁——得顺着
final_blocking_session直捣源头
还原阻塞链不能靠 CONNECT BY,得用 sample_id 递减追踪
ASH 是滚动内存表,每秒一条记录,sample_id 严格递增。用 CONNECT BY PRIOR blocking_session = session_id 会强行把不同时刻的会话拼在一起,比如把上午 9:45 的会话 A 和下午 3:20 的会话 B 错误关联。
真实阻塞路径得聚焦同一会话在连续时刻的行为:先锁定一个高频等待的 session_id 和 session_serial#,再查它前后几秒的样本:SAMPLE_ID BETWEEN X-2 AND X+2,观察 event 是否出现 enq: TX - row lock contention → db file sequential read → cursor: pin S wait on X 这类典型连锁。
- 别用
sample_id = PRIOR sample_id - 1强制“前后秒”关联——采样可能跳过,造成伪链 - 阻塞关系不是持续存在的,同一对会话在不同采样点可能反复出现/消失
- 若多个会话都指向同一个
sql_id,且操作同一张表的主键或唯一索引列,优先检查事务是否未提交
ASH 本身不支持直接递归 CTE,必须先物化中间结果
Oracle 12c+ 支持 WITH RECURSIVE,但 v$active_session_history 是动态性能视图,不能直接用于递归查询初始集(ORA-32043 报错)。想展开 A→B→C→D 链,得先物化数据再算。
做法分两步:先用 WITH 子句把目标窗口数据捞进临时集,再用递归 CTE 构建层级。重点校验三个一致性:时间(同一 sample_time 或相邻秒级)、实例号(inst_id = blocking_inst_id)、序列号(session_serial# = blocking_session_serial#)。
- RAC 下漏掉
blocking_inst_id = inst_id条件,会把其他节点的会话当成阻塞者 - 物化时别用
SELECT *,只取关键字段:sample_id,session_id,session_serial#,blocking_session,blocking_session_serial#,blocking_inst_id,event - 物化后的临时集再跑递归 CTE,才能安全构建多级链,避免跨时间、跨实例错连
阻塞链本质是瞬态现象,采样精度、实例一致性、时间窗口边界这三点一旦松动,整条链就不可信。别指望一条 SQL 查出完整链条——它需要你先圈定可疑会话,再手工验证每一跳的上下文。











