DBAtlas · 数据库运维图谱

死锁分析

症状

出现 'deadlock detected'、'ORA-00060'、'chosen as deadlock victim'——事务相互锁住,其中一个被中止。

1. 死锁是正常现象,但不应频繁发生

数据库会检测到死锁并通过选择牺牲者来解决——这是设计使然。目标是降低发生频率。应用应重试被选为牺牲者的事务。首先获取死锁图。

2. 获取死锁图/详情

哪两个(或更多)会话、哪些资源、哪些锁模式发生了冲突?

Oracle

-- Check the trace file referenced in the alert log (deadlock graph). Also:
SELECT * FROM dba_hist_active_sess_history WHERE event LIKE 'enq: TX%' ORDER BY sample_time DESC;

PostgreSQL

-- log_lock_waits=on; deadlock details are in postgresql.log. Check the deadlock_timeout setting.

MySQL

SHOW ENGINE INNODB STATUS\G  -- LATEST DETECTED DEADLOCK section

SQL Server

-- Deadlock XML in the system_health Extended Events session (ring_buffer, recent events):
SELECT x.ev.value('@timestamp','datetime2') AS event_time, x.ev.query('.') AS deadlock_xml
FROM (SELECT CAST(t.target_data AS XML) td FROM sys.dm_xe_session_targets t
      JOIN sys.dm_xe_sessions s ON s.address = t.event_session_address
      WHERE s.name = N'system_health' AND t.target_name = N'ring_buffer') r
CROSS APPLY r.td.nodes('//RingBufferTarget/event[@name="xml_deadlock_report"]') AS x(ev);
-- For longer history, the event_file target:
-- SELECT CAST(event_data AS XML) FROM sys.fn_xe_file_target_read_file(N'system_health*.xel', NULL, NULL, NULL) WHERE object_name = N'xml_deadlock_report';

3. 消除冲突模式

最常见的原因:两个事务以相反的顺序访问资源。在所有代码路径中以相同的顺序访问资源。第二常见的原因:缺失索引导致大范围的范围锁——添加所需的索引。

4. 缩短锁的持续时间并缩小范围

保持事务简短(不要在事务内包含用户交互)。选择合适的隔离级别。必要时尽早获取行锁(使用确定性排序的 SELECT ... FOR UPDATE)。

5. 应用中的重试必不可少

死锁无法完全消除;为牺牲者事务实现自动重试(指数退避)。这样用户就不会看到错误。

在 DBAtlas 中打开 →