死锁分析需交叉印证alert日志与ash:alert中“global enqueue services deadlock detected”含did和trace路径,用于定位会话;ash须在死锁发生后1分钟内按精确时间戳过滤sample_time,查找互锁会话。

死锁发生后,不能只查 Alert 日志或只扫 ASH —— 两者必须交叉印证:Alert 告诉你“发生了”,ASH 告诉你“谁在那一秒卡住了谁”。
Alert 日志里看到 Global Enqueue Services Deadlock detected 就该立刻行动
这条日志不是事后总结,而是 Oracle LMD 进程实时检测到环形等待后写入的信号。关键点是它附带了 trace 文件路径和 DID(Deadlock ID),比如:Global Enqueue Services Deadlock detected (DID = 8_0_1)。这个 DID 是后续在 trace 中定位具体会话对的唯一入口。
- 别等 AWR 报告生成,也别只盯着
v$session_wait—— 死锁一解,等待状态就清空了 - 立刻去对应 trace 文件(如
/u01/PROD/oracle/diag/rdbms/prod/PROD3/trace/PROD3_lmd0_123449.trc)搜DID = 8_0_1,里面会列出参与死锁的两个 session 的sid、serial#、SQL ID 和锁对象 - Alert 日志里的时间戳(如
Mon Apr 01 15:17:06 2019)要精确到秒,这是你在 ASH 中过滤sample_time的起点
V$ACTIVE_SESSION_HISTORY 必须限定“黄金 60 秒”内查
死锁持续通常不到 1 秒,而 ASH 内存缓冲区采样间隔约 1 秒,但不是严格等距。查太宽(比如 5 分钟)会导致噪音淹没真实互指信号;查太窄(比如只查 1 行)可能刚好错过采样点。
- 用
sample_time BETWEEN SYSDATE - 1/1440 AND SYSDATE(即最近 1 分钟)作为基础窗口,再根据 Alert 日志时间微调,例如:sample_time >= TIMESTAMP '2026-09-17 18:22:30' AND sample_time - 只筛
event IN ('enq: TX - row lock contention'),排除enq: TX - allocate ITL entry(那是 ITL 不足,不是真死锁) - 必须同时包含等待方和持有方:
blocking_session IS NOT NULL OR session_state = 'WAITING',否则可能漏掉刚释放锁、但被采样到的持有者 -
blocking_session_serial#必须和blocking_session同时非空,单独blocking_session为数字但blocking_session_serial#为空,大概率是采样不完整,不可信
怎么从 ASH 数据里人工识别互锁会话对
ASH 不会标“死锁”,但你可以靠三组条件在同一 sample_time 下拼出循环等待链。核心是“互指 + 同事件 + 锁参数交叉”。
- 找两个会话 A 和 B,满足:
A.blocking_session = B.session_id且B.blocking_session = A.session_id - 两者的
event都必须是enq: TX - row lock contention,且sql_id相同或高度相似(说明同业务逻辑并发更新) - 检查
p1(undo segment#)和p2(slot#):若A.p1 = B.p2且B.p1 = A.p2,基本可确认 TX 锁互持(注意:这个匹配不是 100% 必现,但出现即强证据) - 别依赖
current_obj#是否相同 —— 死锁常发生在不同行甚至不同表(如父子表级联更新),重点看锁资源标识(p1/p2)和阻塞关系
DBA_HIST_ACTIVE_SESS_HISTORY 只能用于归因,不能用于定位
历史表采样滞后(默认每 10 秒刷一次)、字段不稳定(19c 前 blocking_session 常为空)、且牺牲者回滚后阻塞链断裂。它不是诊断入口,而是证据补全工具。
- 必须用 V$ACTIVE_SESSION_HISTORY 先锁定精确到秒的
sample_time和会话对,再拿这对值去查历史表 - 查历史表时加硬条件:
sample_time = TO_TIMESTAMP('2026-09-17 18:22:37', 'YYYY-MM-DD HH24:MI:SS')+session_id IN (A_sid, B_sid) - 目的不是再找一遍谁卡谁,而是看这俩会话在死锁前后 5 分钟内是否反复出现同类等待(判断是否模式化问题)、是否涉及同一对象或 SQL(定位业务根源)
- 如果历史表里查不到那条记录,不要怀疑操作,大概率就是采样错过了——这时应以内存视图
v$active_session_history为准
真正难的不是写出那几条 SQL,而是拿到 Alert 时间戳后,能否在 30 秒内决定采样窗口的起止秒数,并意识到 p1/p2 交叉匹配比 current_obj# 更可靠。很多 DBA 卡在第一步:把 Alert 日志当故事读完,却没把它当成 ASH 查询的时间锚点。











