必须用GV$ACTIVE_SESSION_HISTORY,因V$ASH仅返回当前实例数据,RAC环境下90%阻塞源在其他节点;需结合blocking_instance、wait_time=0和event三条件精准定位根因会话。

必须用GV$ACTIVE_SESSION_HISTORY,单查V$ASH会漏掉90%阻塞源
Oracle RAC环境下,v$active_session_history只返回当前实例的采样数据,而真实阻塞者可能在另一个节点上。直接查它,blocking_session字段为空或指向本地“中间人”,根本找不到源头。生产环境必须用gv$active_session_history,它跨实例聚合,且每个记录带inst_id字段标识来源节点。
常见错误是加了WHERE blocking_session IS NOT NULL却没指定inst_id或blocking_instance,结果只扫到本节点的碎片信息。实操建议:
- 显式过滤
blocking_instance IS NOT NULL,避免把本节点空值当有效结果 - 若已知问题发生在特定节点(比如实例2),加
AND inst_id = 2缩小范围,再反查该节点上的持锁会话 - 别用
SELECT *——gv$视图数据量是单实例的N倍,不加时间窗会卡死
关键条件:event + wait_time = 0 + blocking_instance三者缺一不可
library cache lock或enq: TX - row lock contention这类事件,在RAC中必须配合wait_time = 0才能确认“正卡着”。因为ASH里wait_time为0表示等待刚发生、尚未超时;非0值可能是历史残留或已响应。漏掉这个条件,会混入大量无效快照。
同时,blocking_instance字段比blocking_session更可靠——它明确指出阻塞者在哪台实例上。实操要点:
-
blocking_session非空但blocking_instance为空?说明阻塞源不在RAC内,可能是单实例DB或外部进程 -
blocking_instance值为1,但查v$instance发现当前实例号是2?说明该记录来自节点1,得切过去查v$session - 若
final_blocking_instance和final_blocking_session都非空,优先用这对字段——它跳过A→B→C级联链,直指源头实例和会话
还原阻塞链不能靠CONNECT BY,得按sample_id递减追踪
ASH是滚动内存表,sample_id严格递增,每秒一条。用CONNECT BY PRIOR blocking_session = session_id强行关联,会把上午9:45的会话A和下午3:20的会话B拼成“阻塞链”,纯属伪相关。真实路径必须聚焦同一会话在连续时刻的行为。
正确做法是:先锁定一个高频等待的session_id,再用SAMPLE_ID倒序查它前5秒的记录,看blocking_session和final_blocking_session是否稳定出现。例如:
SELECT sample_id, session_id, final_blocking_session, final_blocking_instance, event FROM gv$active_session_history WHERE session_id = 1234 AND sample_time > SYSDATE - 1/1440 ORDER BY sample_id DESC FETCH FIRST 5 ROWS ONLY;
若这5条记录里final_blocking_session始终是5678、final_blocking_instance始终是1,那基本可断定节点1的会话5678是根因。
RAC下final_blocking_session为0,说明它是根阻塞源
在gv$active_session_history里,如果某条记录的final_blocking_session = 0或为空,且event是enq: TX - row lock contention,那就不用再往下追了——它就是那个没提交事务、持有行锁的会话。这时候要立刻切到对应实例(通过final_blocking_instance确认),查v$session实时状态:
SELECT sid, serial#, username, sql_id, event, logon_time, last_call_et FROM v$session WHERE sid = <final_blocking_session> AND status = 'ACTIVE';
注意:v$session是实时视图,不能和gv$active_session_history直接JOIN。两个视图之间只能靠SID+INST_ID人工串查。最容易被忽略的是:查到SID后,得立刻确认last_call_et是否远大于0——如果超过300秒,大概率是应用端忘了commit,而不是数据库故障。


















