ASH是唯一能回溯死锁发生前1–30秒内完整等待链的手段,因V$SESSION在死锁后仅留INACTIVE状态且字段清空,而ASH每秒采样并保留SESSION_ID、BLOCKING_SESSION、SQL_ID等秒级精确信息。

ASH 不能直接捕获“全面死锁”本身,但能精准还原死锁发生前 1–30 秒内的完整等待链——这是定位根因的黄金窗口。
为什么ASH比V$SESSION更适合死锁回溯
死锁发生瞬间,Oracle 内核会自动中断其中一个会话(报 ORA-00060),该会话状态迅速变为 INACTIVE,V$SESSION 中只留下模糊的 STATE = 'INACTIVE' 和空 SQL_ID;而 ASH 在死锁触发前每秒采样一次活动会话,保留了完整的 SESSION_ID、SQL_ID、EVENT、BLOCKING_SESSION 和堆栈信息,时间精度达秒级。
- ASH 默认保留最近 30 分钟数据(由
_ash_disk_filter_ratio和DBA_HIST_ASH归档策略决定),远超V$SESSION的瞬时性 - 死锁不是“单点事件”,而是“链式等待收敛”:A 等 B、B 等 C、C 又等 A —— ASH 的连续采样天然支持按
SESSION_ID+SNAP_ID排序回放 -
V$SESSION的BLOCKING_SESSION字段在死锁后常被清空或错乱,ASH 中的blocking_session和blocking_session_serial#在采样时刻是真实有效的
用ASH提取等待链的核心SQL(需在死锁发生后立即执行)
关键不是查“当前谁在等”,而是查“死锁发生前 5 秒内,哪些会话持续处于等待且构成闭环”。以下语句基于 DBA_HIST_ACTIVE_SESS_HISTORY(归档ASH)或 V$ACTIVE_SESSION_HISTORY(内存ASH),按时间倒序抓取高置信度链路:
SELECT sample_time, session_id, session_serial#, sql_id, event, blocking_session, blocking_session_serial#, current_obj#, program FROM dba_hist_active_sess_history WHERE sample_time >= SYSDATE - INTERVAL '5' SECOND AND event LIKE 'enq:%' AND session_state = 'WAITING' ORDER BY sample_time DESC, session_id;
- 必须加
session_state = 'WAITING'过滤,排除 CPU 活动干扰 -
event LIKE 'enq:%'覆盖所有队列锁(TM、TX、DDL 等),比只查enq: TX - row lock contention更全面 - 若用
V$ACTIVE_SESSION_HISTORY,注意它只保留在内存中(默认约 1GB 缓冲区),大压力下可能被覆盖,优先查DBA_HIST_ACTIVE_SESS_HISTORY - 结果中若发现 A→B→C→A 的
blocking_session循环(如 session_id=101 的 blocking_session=102,102 的 blocking_session=103,103 的 blocking_session=101),即为死锁链证据
如何关联到具体SQL和对象(避免只看到“enq: TM - contention”)
光知道“在等 TM 锁”没用,得定位到是哪条 SQL、操作哪张表、是否隐含 DDL。ASH 本身不存 SQL 文本,需通过 SQL_ID 关联:
- 对每个关键
SQL_ID,立即查V$SQL获取SQL_TEXT:SELECT sql_text FROM v$sql WHERE sql_id = 'abc123xyz' - 若
SQL_ID为空(常见于 PL/SQL 匿名块),改查PREV_SQL_ID或用V$SESSION补全:SELECT prev_sql_id FROM v$session WHERE sid = 101 -
CURRENT_OBJ#是对象编号,转表名用:SELECT object_name FROM dba_objects WHERE object_id = 12345 - 特别注意
PROGRAM字段:若为oracle@host (J000),可能是作业(JOB)引发的隐式 DDL;若为jdbc thin client,需回溯应用层事务边界
容易被忽略的三个关键点
死锁分析中最常卡住的地方,往往不在查询本身,而在数据解读逻辑:
- ASH 的
SAMPLE_TIME是采样时刻,不是等待开始时刻 —— 某个会话在 14:02:01 出现在 ASH 并显示blocking_session = 102,不代表它从 14:02:01 才开始等,可能已等了 8 秒;需结合多个采样点判断持续性 - “全面死锁”常伴随大量会话被连锁阻塞(A 等 B,B 等 C,C 等 D…D 等 A),但 ASH 只记录活动会话 —— 若某会话已提交或回滚,它不会出现在 ASH 中,链路看起来就断了;此时必须交叉验证
DBA_BLOCKERS和DBA_WAITERS(哪怕只有一瞬) - 12c+ 版本中 TRUNCATE 隐式请求 DDL 锁,若与长事务 UPDATE 同时发生,会表现为
enq: DDL - contention和enq: TM - contention并存 —— 这类混合锁等待在 ASH 中需合并观察,不能只盯单一事件


















