ash视图无“历史阻塞链”字段,需基于blocking_session等三字段递归关联构建多级阻塞链,须限定时间范围、校验实例一致性,并先物化gv$active_session_history数据再用递归cte计算。
ash视图里没有“历史阻塞链”这个现成字段
oracle 12c 的 v$active_session_history(ash)本身不存储完整的阻塞链快照,它只记录每秒采样时会话的瞬时状态,包括 blocking_session、blocking_session_serial#、blocking_inst_id 这三个字段。所谓“多级阻塞链”,比如 a → b → c → d,必须靠递归关联这些字段拼出来——不是查一次就能出结果,得用自连接或递归 cte。
常见错误是直接 JOIN v$ash a ON a.session_id = b.blocking_session 却忽略实例号、序列号、采样时间窗口,导致跨实例匹配错乱,或把不同时间点的阻塞关系强行串成一条“伪链”。
- 必须限定时间范围:
sample_time BETWEEN ... AND ...,否则跨数小时的数据混在一起毫无业务意义 - 必须校验实例一致性:
a.blocking_inst_id = b.inst_id,RAC 环境下漏掉这个条件会把其他节点的会话当成阻塞者 - 阻塞关系不是全时段持续的,同一对会话可能在不同采样点反复出现/消失,不能简单去重后当“稳定链路”看待
用递归 CTE 构建阻塞层级(LEVEL + CONNECT BY 不适用)
Oracle 12c 支持 WITH RECURSIVE(注意:需 12.1.0.2+ 且启用 COMPATIBLE >= 12.1.0),但 v$active_session_history 是动态性能视图,不能直接用于递归查询的初始集(ORA-32043 不允许在 WITH 子句中引用动态性能视图)。实际可行方案是先物化中间结果:
WITH ash_base AS (
SELECT inst_id, session_id, session_serial#, blocking_session,
blocking_session_serial#, blocking_inst_id, sample_time,
sql_id, event, p1, p2
FROM gv$active_session_history
WHERE sample_time >= SYSDATE - 1/24 -- 最近1小时
AND blocking_session IS NOT NULL
),
block_chain (inst_id, sid, serial#, blocker_sid, blocker_serial#, blocker_inst, lvl, path) AS (
-- 叶子节点:被阻塞但自己没阻塞别人(即不在 ash_base 的 blocking_session 列中出现)
SELECT a.inst_id, a.session_id, a.session_serial#,
a.blocking_session, a.blocking_session_serial#, a.blocking_inst_id,
1 AS lvl,
TO_CHAR(a.session_id) || ' <p>关键点:初始集必须是“终端被阻塞者”,不是随便挑一个会话开始;<code>lvl 是硬性防护,ASH 采样间隔为1秒,长链往往意味着严重锁争用,优先人工介入而非依赖SQL深挖。</code></p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6971" title="QuantOracle"><img
src="https://img.php.cn/upload/skill/000/000/081/179120536643782.jpg" alt="QuantOracle" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6971" title="QuantOracle" class="overflowclass">QuantOracle</a>
<p class="overflowclass">63个确定性量化金融计算器 + 10个通过MCP的复合工作流。期权定价、Greeks、奇异衍生品、风险指标、投资组合优化……</p>
</div>
<a rel="nofollow" href="/xiazai/skill6971" title="QuantOracle" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h3>为什么不能用 v$session_longops 或 dba_hist_active_sess_history?</h3><p><code>v$session_longops</code> 记录的是长时间运行操作(如排序、哈希连接),和阻塞无关;<code>dba_hist_active_sess_history</code> 虽然存的是ASH历史快照,但默认只保留1小时(受 <code>statistics_level</code> 和 AWR 保留策略影响),且每分钟才写入一次汇总数据,丢失大量秒级细节——你看到的可能是“A阻塞B持续60秒”,但真实情况是A每5秒阻塞B一次、每次200ms,这种脉冲式阻塞在 <code>dba_hist_active_sess_history</code> 里根本无法还原。</p>
- 查实时问题,只用
gv$active_session_history(注意是gv$,非v$,RAC 必须跨实例看) - 查1小时前的问题,先确认 AWR 是否启用了 ASH 采样(
SELECT dbms_workload_repository.ash_get_top_sql( ... )可间接验证) - 想长期追踪阻塞模式,应配合
DBMS_MONITOR.SESSION_TRACE_ENABLE对可疑会话开启10046跟踪,ASH只是第一响应手段
容易被忽略的采样偏差和锁类型混淆
ASH 每秒采样一次,但只捕获当时处于“等待”或“CPU运行”状态的会话。如果阻塞发生在两次采样之间(比如锁持有时间 event 字段决定阻塞性质,enq: TX - row lock contention 和 enq: TM - contention 处理方式完全不同,但它们在阻塞链里都表现为 blocking_session 非空。
- 务必检查
event和p1text/p2text:用SELECT event, p1text, p2text FROM v$event_name WHERE name = '...'解码参数含义 - 不要假设所有
blocking_session都指向 DML 语句:可能是DDL(如 ALTER TABLE)持有 TM 锁,阻塞了后续所有访问该表的会话 - 对于
library cache lock类阻塞,blocking_session可能指向正在做硬解析的会话,此时真正瓶颈是 shared pool 或 SQL 写法,不是锁本身
链越长,越要回到源头看第一个阻塞者的 sql_id 和执行计划,而不是在中间层反复关联。










