第六期:并发控制(下)—— 死锁检测、分析与消除
Clyde Jin
04-25
DBA
164

第六期:并发控制(下)—— 死锁检测、分析与消除

1. 死锁的定义与必要条件

死锁:两个或多个事务各自持有对方需要的资源,且都不释放,导致永久阻塞。

四个必要条件(全部满足才会死锁):

| 条件 | 说明 | 示例 |

|——|——|——|

| 互斥 | 资源一次只能被一个事务持有 | 排他锁(X)同时只能一个事务持有 |

| 持有并等待 | 持有资源的同时请求其他资源 | 事务A持有表T1锁,请求表T2锁 |

| 不可抢占 | 已持有的锁不能被强制释放 | SQL Server不会主动剥夺锁 |

| 循环等待 | 事务间形成等待环 | A等B → B等C → C等A |

现象解释

  • 为什么高并发系统更容易死锁?因为事务间交错执行的概率增加,更容易形成循环等待。

  • 为什么死锁通常发生在多个表之间或同一表的不同行?因为需要形成”互相等待”的环。

2. SQL Server的死锁检测与处理机制

死锁检测

  • 锁监视器线程(Lock Monitor):每5秒启动一次,检测系统内是否有死锁。

  • 等待图(Wait Graph):维护资源与等待关系的有向图,检测到循环即判定死锁。

  • 高频检测:当死锁发生频率较高时,检测频率自动提升(可低至100ms)。

死锁处理


1. 检测到死锁循环

2. 选择"牺牲品"(Victim)

3. 终止牺牲品事务,回滚其所有操作

4. 释放该事务持有的所有锁

5. 让其他事务继续运行

6. 向牺牲品客户端返回错误号 1205

牺牲品选择依据

  • 死锁优先级SET DEADLOCK_PRIORITY(LOW / NORMAL / HIGH / -10~10数值)

  • 优先级最低的会话被选中

  • 相同优先级时,选择回滚代价最小的事务

  • 默认所有会话优先级为 NORMAL(0)


-- 设置当前会话为低优先级(更容易被杀)

SET DEADLOCK_PRIORITY LOW;

-- 设置关键事务为高优先级(不容易被杀)

SET DEADLOCK_PRIORITY HIGH;

现象解释

  • 为什么重试能解决死锁错误?因为死锁是偶发的,重新执行通常能成功。

  • 为什么长事务更容易成为牺牲品?回滚代价大,但在相同优先级时,SQL Server会选择回滚代价小的(不是长的,而是修改少的)。

3. 典型死锁场景与案例

场景一:两个事务交叉更新两张表


事务A:                事务B:

UPDATE T1 SET ...      UPDATE T2 SET ...

WAITFOR '00:00:01'     WAITFOR '00:00:01'

UPDATE T2 SET ...      UPDATE T1 SET ...

锁过程:

  1. A持有T1的X锁,请求T2的X锁 → 等待B释放T2

  2. B持有T2的X锁,请求T1的X锁 → 等待A释放T1

  3. 死锁形成 → SQL Server杀死其中一个

场景二:同一表上的行级锁死锁


事务A:                              事务B:

BEGIN TRAN                           BEGIN TRAN

UPDATE Orders SET Status=1           UPDATE Orders SET Status=1

WHERE OrderID=101                    WHERE OrderID=102

-- 此时A持有101的行X锁,B持有102的行X锁

SELECT * FROM Orders                SELECT * FROM Orders

WHERE OrderID=102                   WHERE OrderID=101

-- 需要共享锁,被B的X锁阻塞          -- 需要共享锁,被A的X锁阻塞

死锁形成!

场景三:范围锁(SERIALIZABLE级别)导致的死锁


-- 事务A:查询并插入缺失行

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRAN

SELECT * FROM Orders WHERE OrderDate = '2024-01-01';  -- 持有范围锁

-- (发现没有数据)

INSERT INTO Orders VALUES ('2024-01-01', ...);  -- 等待事务B释放

-- 事务B:同样的操作,死锁形成

场景四:聚集索引与非聚集索引间的死锁


事务A:通过非聚集索引查找,更新聚集索引页

事务B:通过聚集索引扫描,更新非聚集索引页

→ 两个索引页形成循环等待

4. 死锁分析工具与方法

方法一:使用系统扩展事件(Extended Events)


-- 创建死锁捕获会话

CREATE EVENT SESSION DeadlockCapture ON SERVER 

ADD EVENT sqlserver.xml_deadlock_report

ADD TARGET package0.event_file(SET filename=N'DeadlockCapture.xel')

WITH (MAX_MEMORY=4096 KB, EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS);

ALTER EVENT SESSION DeadlockCapture ON SERVER STATE = START;

方法二:启用跟踪标志(Trace Flags)

| 跟踪标志 | 作用 |

|———-|——|

| TF 1204 | 以文本格式输出死锁信息到错误日志 |

| TF 1222 | 以XML格式输出死锁信息到错误日志(更详细) |

| TF 1224 | 禁用锁升级(高并发场景慎用) |


-- 启用死锁记录

DBCC TRACEON(1204, 1222, -1);

-- 查看当前跟踪标志

DBCC TRACESTATUS;

方法三:分析死锁图的XML结构

死锁图包含三个关键部分:

  • ****:参与死锁的资源(表、页、键)

  • ****:参与死锁的事务及其持有/请求的锁

  • ****:被选中的牺牲品


<deadlock>

&#x20; <victim-list>

&#x20;   <victimProcess id="process2" />

&#x20; </victim-list>

&#x20; <process-list>

&#x20;   <process id="process1" waitresource="KEY: 5:720576... (1234567890)" />

&#x20;   <process id="process2" waitresource="KEY: 5:720576... (0987654321)" />

&#x20; </process-list>

&#x20; <resource-list>

&#x20;   <keylock objectname="MyDB.dbo.Orders" />

&#x20; </resource-list>

</deadlock>

方法四:使用DMV实时监控


-- 查看当前死锁相关的请求

SELECT session_id, wait_type, wait_resource, blocking_session_id

FROM sys.dm_exec_requests

WHERE blocking_session_id > 0;

-- 查看锁等待图(仅当前状态)

SELECT * FROM sys.dm_tran_locks 

WHERE request_status = 'WAIT';

5. 死锁消除策略

策略一:统一访问顺序(最重要)

  • 所有事务以相同顺序访问表(如先T1后T2)

  • 所有事务以相同顺序访问行(如ORDER BY强制排序)


-- 坏:两个事务顺序不同

-- 好:统一使用ORDER BY

SELECT * FROM Orders WITH(UPDLOCK) 

WHERE OrderID IN (101, 102)

ORDER BY OrderID;  -- 总是先锁101,后锁102

策略二:缩短事务长度

  • 减少事务内执行的语句数

  • 不要在事务中等待用户输入

  • 尽早提交或回滚

策略三:降低隔离级别

  • 启用RCSI(READ_COMMITTED_SNAPSHOT),读不阻塞写

  • 使用快照隔离(SNAPSHOT ISOLATION)

  • 报表查询允许脏读(READ UNCOMMITTED或NOLOCK)


-- 启用快照隔离(数据库级别)

ALTER DATABASE YourDB SET ALLOW_SNAPSHOT_ISOLATION ON;

-- 事务级别使用

SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

策略四:优化索引

  • 添加覆盖索引,避免书签查找

  • 减少扫描,尽快定位目标行

  • 避免非聚集索引的锁与聚集索引锁形成循环

策略五:使用行版本控制替代锁

  • 开启RCSI后,SELECT使用行版本,UPDATE使用X锁

  • 读写不互斥,大幅减少死锁


-- 检查RCSI是否开启

SELECT name, is_read_committed_snapshot_on 

FROM sys.databases 

WHERE name = 'YourDB';

策略六:死锁重试逻辑(应用层)


// C# 示例

int retryCount = 0;

int maxRetries = 3;

bool success = false;

while (!success && retryCount < maxRetries)

{

&#x20;   try

&#x20;   {

&#x20;       ExecuteTransaction();

&#x20;       success = true;

&#x20;   }

&#x20;   catch (SqlException ex) when (ex.Number == 1205)  // 死锁错误号

&#x20;   {

&#x20;       retryCount++;

&#x20;       Thread.Sleep(100 * retryCount);  // 指数退避

&#x20;   }

}

6. 常见死锁误区与真相

| 误区 | 真相 |

|——|——|

| 死锁只发生在多个表之间 | 同一张表的不同索引页也可形成死锁 |

| 索引越多越容易死锁 | 合理的覆盖索引能减少书签查找,反而降低死锁 |

| NOLOCK能完全避免死锁 | NOLOCK读不申请锁,但写操作仍可能死锁 |

| 死锁和阻塞是一回事 | 阻塞是等待锁释放;死锁是循环等待,且会被自动处理 |

| 增加索引能解决所有死锁 | 索引能减少扫描,但访问顺序错误仍会死锁 |

7. 死锁排查检查清单


□ 捕获死锁图(启用1222跟踪标志)

□ 分析死锁图,找出参与的事务和资源

□ 查看两个事务的SQL语句和执行计划

□ 检查事务的隔离级别(是否使用了SERIALIZABLE?)

□ 检查访问顺序是否一致(表顺序、行顺序)

□ 检查是否有长事务未提交

□ 检查索引设计(是否扫描过多?)

□ 考虑开启RCSI(如果读多写少)

□ 检查是否使用了非聚集索引书签查找

□ 在应用层实现重试逻辑

第六期小结

死锁由四个必要条件共同形成,SQL Server通过锁监视器检测并选择牺牲品自动解决。死锁图(TF 1222)是分析的关键工具。消除死锁最有效的方法是统一访问顺序、缩短事务长度和开启行版本控制(RCSI)。理解锁的粒度和等待关系,才能在设计中避免死锁,或在发生后快速定位根因。

下期预告:查询优化器与执行计划 —— 如何读懂执行计划?为什么统计信息如此重要?何时应该干预优化器的选择?

Star
Donate
第五期:并发控制(上)—— 隔离级别、锁与锁升级
Previous
第七期:查询优化器与执行计划 —— 如何读懂与干预
Next

Leave a comment

Registration is not required

Clyde Jin
303 Articles
0 Comments
0 Like
Recent Posts

HiddenMerit Daily · Issue 60

📊 HiddenMerit Daily · Issue 60 Focus on Database Frontiers, Practical Insights for DBAs July 22, 2026 | 5 Selected Global Breaking News 01|Oracle Releases Largest Quarterly Patch in History: 1,449 Patches Fix 1,235 CVEs, 261 Critical On July 21, Oracle released its July 2026 Critical Patch Update (CPU), setting a record for the largest single patch release in the company’s history. This CPU contains 1,449 security patches fixing 1,235 independent CVEs across 32 Oracle product families, of which 261 patches are rated Critical. Patch Distribution by Product Family: Product Family Patches Remotely Exploitable Without Authentication Oracle E‑Business Suite 410 45 Oracle Fusion Middleware 355 219 Oracle Communications 168 122 Oracle MySQL 54 9 Oracle Database Server 15 6 Context for This Patch: Oracle had already issued an urgent “Prepare Now” warning a week earlier, emphasising that AI is fundamentally lowering the barrier to discovering and exploiting vulnerabilities – frontier AI models can analyse software changes, reverse‑engineer security patches, and develop attack paths at unprecedented speed. Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. Oracle strongly recommends that customers immediately test and deploy this update in their monthly patch cycles. […]

HiddenMerit Daily · Issue 59

📊 HiddenMerit Daily · Issue 59 Focus on Database Frontiers, Practical Insights for DBAs July 21, 2026 | 5 Selected Global Breaking News 01|Oracle Issues Urgent Warning: July 21 Release Update to Fix Large Number of High‑Risk Vulnerabilities, Immediate Deployment Recommended On July 13, Oracle issued an urgent security warning, strongly recommending that all customers running supported Oracle Database versions (including Oracle Database 19c and Oracle AI Database 26ai) immediately test and deploy the Release Update (RU) after its release on July 21. Background: New frontier AI models are significantly lowering the barrier to discovering and exploiting software vulnerabilities – these models can identify weaknesses, analyse software changes, reverse‑engineer security patches, and develop potential attack paths at unprecedented speed and scale. AI models are also becoming increasingly adept at combining multiple weaknesses across the application and data stack into complex attacks, even when individual weaknesses do not themselves pose a serious risk. As a result, protecting systems solely at the network or application layer is no longer sufficient; enterprises must protect the entire technology stack. Fixes Included in This RU: Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. The upcoming […]

HiddenMerit Daily · Issue 58

📊 HiddenMerit Daily · Issue 58 Focus on Database Frontiers, Practical Insights for DBAs July 20, 2026 | 5 Selected Global Breaking News 01|CAICT: Domestic Databases Enter Core System “Deep Water,” AI‑Native Leads New Industry Landscape On July 9, at the 2026 Trustworthy Database Development Conference, CAICT released the “Database Development Research Report (2026).” The report notes that domestic databases have basically completed peripheral system replacement and have officially entered the critical business system breakthrough phase. Key Data: The global database market reached $131.6 billion in 2025 (approximately RMB 894.09 billion). The Chinese database market reached $9.49 billion in 2025 (approximately RMB 64.48 billion), and is expected to reach RMB 97.974 billion by 2028, with a CAGR of 13.06%. The number of domestic database vendors has shrunk from a peak of 167 to 94, with a clear head‑concentration effect and an intensifying “Matthew effect.” AI‑Native Becomes the Main Theme: The report points out that database technology is accelerating its evolution toward the AI‑native direction, and the global database industry is entering a new phase of landscape restructuring. The role of databases is upgrading from “underlying support systems” to “core engines enabling intelligent decision‑making and business innovation.” AI agents are becoming […]

HiddenMerit Daily · Issue 56

📊 HiddenMerit Daily · Issue 56 Focus on Database Frontiers, Practical Insights for DBAs July 6, 2026 | 5 Selected Global Breaking News 01|Kingware Releases Manufacturing Scenario Database Evolution White Paper: SQL Server Replacement Enters “Deep Water” On July 5, CETC Kingware published a technical article titled “Database Evolution in Manufacturing Scenarios: How Kingware Replaces SQL Server,” pointing out that the data surge on industrial shop floors has exceeded the processing capacity of single‑node systems. Traditional database architectures that rely on vertical scaling are facing unprecedented performance challenges. Over the next 1‑3 years, manufacturing enterprises will no longer face only the “choice of replacement,” but must answer the strategic question: “How do we build an autonomous data foundation in the context of de‑IOE?” Three Paradigm Shifts: Hybrid Workloads Become the Norm: The IT architecture of modern factories is shifting from separated OLTP and OLAP to HTAP mode. The same data system must simultaneously handle tens of thousands of device instruction writes per second and minute‑level production report analysis. Distributed Architecture Becomes a Hard Requirement: When a single table exceeds 100 million rows with daily increments exceeding 1 million rows, the index maintenance cost of traditional single‑node databases rises exponentially. Autonomous […]
生成中...
扫描二维码
扫描二维码