v$active_session_history看不到真正的final blocker,因其仅采样本实例活动会话,而final blocker可能已退出、提交、回滚或处于非活动状态,ash不记录空闲、结束或刚释放锁即消失的会话。
查 v$active_session_history 为什么看不到真正的 final blocker?
因为 v$active_session_history 默认只记录本实例采样到的会话状态,而 final blocker(最终阻塞者)可能已退出、被 kill、或处于非活动状态(如已提交/回滚/断连),ash 不会为它保留样本。更关键的是:ash 只捕获 活动等待中 的会话,不记录空闲、已结束、或刚释放锁就消失的会话。
常见误判现象:
- 看到大量会话卡在
enq: TX - row lock contention,但blocking_session列全为空 -
final_blocking_session有值,但查v$session发现该 SID 已不存在(STATUS = 'INACTIVE'或查无此行) - 同一时间点多个会话显示相同
blocking_session,但该会话在 ASH 中无对应等待事件记录
这时不能直接认定“没阻塞源”,而应转向 dba_hist_active_session_history(AWR 历史表)或结合 v$lock + v$session 实时快照交叉验证。
final_blocking_session 为空却持续 Hang,该查什么?
当 final_blocking_session IS NULL 但系统整体响应迟缓、大量会话 WAITING,大概率不是传统锁问题,而是资源耗尽型 Hang —— 比如 shared pool latch 争用、library cache pin、或 log file switch 等系统级瓶颈。
优先执行以下检查:
- 查
v$system_event中非空闲类等待的time_waited_micro总和,重点关注latch: shared pool、library cache: mutex X、log file switch (checkpoint incomplete) - 用
SELECT * FROM v$session WHERE state = 'WAITING' AND event NOT LIKE 'SQL*Net%'看是否集中卡在某类底层资源上 - 检查
v$process的pga_used_mem和v$sgastat的 free memory,确认是否存在内存碎片或分配失败 - 对 RAC 环境,必须查
gv$active_session_history而非单实例v$视图,避免漏掉跨节点 GC 阻塞(如gc current block 2-way在节点2发起、节点1响应,但节点1的v$不记请求方)
如何从 ASH 推断出已消失的阻塞源头?
虽然 Final Blocker 本身不在当前 ASH 样本里,但它留下的“痕迹”仍在:比如长时间持有锁后突然释放,会在 ASH 中表现为一批会话在极短时间内(毫秒级)从 enq: TX 切换为 SQL*Net message from client;或出现大量 enq: TX - allocate ITL entry 后紧接 db file sequential read,暗示热点块争用。
实操建议:
- 用时间窗口聚合:按
sample_time分钟级分组,统计COUNT(*)和AVG(time_waited),找突增拐点 —— Hang 往往始于某分钟内等待数陡升 - 关联
sql_id和object_id:即使blocking_session为空,若多个等待会话的sql_id相同且指向同一张表(通过dba_hist_sql_plan反查),大概率是该 SQL 的 DML 引发了隐式锁或 ITL 争用 - 注意
session_state = 'ON CPU'的异常峰值:若大量会话标为 ON CPU 但实际无有效 SQL 执行(sql_id IS NULL),可能是 spin lock 或 mutex 死循环,需立刻查 OS 层线程栈
为什么 gv$active_session_history 比 v$ 更适合诊断 Hang?
因为 Hang 往往是跨组件、跨实例、跨时间的复合问题,单实例 v$ 视图就像只有一只眼睛看世界 —— 它看不到远程实例的请求、看不到磁盘 I/O 的真实延迟、也看不到已过去 60 秒但仍在影响当前会话的锁历史。
关键差异点:
-
gv$包含inst_id列,可区分等待发生在哪个 RAC 节点;而gc current block 2-way类等待若只查本地v$,等于主动屏蔽了 50% 的线索 -
gv$active_session_history的采样是各实例独立完成再汇总,虽有轻微延迟(通常 blocking_inst_id 非零的跨节点阻塞 - 某些等待事件(如
DFS lock handle)只在gv$中体现,v$中压根不出现 - 执行
SELECT COUNT(*) FROM gv$active_session_history若远小于SELECT COUNT(*) FROM v$active_session_history(同一时间),说明部分实例未正常上报,本身就是 Hang 的早期信号
真正容易被忽略的点:ASH 数据不是“实时录像”,而是“每秒快照”。一次 Hang 可能由连续 3 个样本点构成 —— 第一个点是阻塞开始,第二个点是等待扩散,第三个点是资源耗尽。跳过任意一个,结论就可能错。











