SQL Server死锁咨询:重复锁条目及锁模式差异等问题
SQL Server 3进程死锁问题分析
一、resource-list中相同ID的keylock重复出现的原因
死锁XML里重复出现相同id的keylock条目,并非存在多个相同的行锁资源,而是SQL Server为了清晰展示不同进程与同一锁资源的交互关系拆分记录的结果。本质上这些重复条目指向的是同一个行级排他锁(X锁),只是分别记录了不同进程对该锁的持有、等待状态。
二、keylock、owner、waiter元素的mode属性区别
- keylock的mode:代表当前锁资源最终被持有的锁模式,是锁资源本身的状态。比如示例中的
mode="X",说明这个行锁当前处于排他锁状态,不允许其他进程获取共享/排他锁。 - owner的mode:代表持有该锁的进程所持有的锁模式。如果
owner节点带有requestType="wait",则表示该进程正在等待获取该模式的锁;若没有该属性,说明进程已成功持有对应模式的锁(如第一个owner的mode="X",表示进程已持有排他锁)。 - waiter的mode:代表等待该锁的进程请求的锁模式。示例中的
mode="S"表示等待进程正在请求共享锁,由于当前锁是排他锁,共享锁请求会被阻塞。
三、死锁发生原因及环境差异问题
死锁根源
虽然每个进程操作唯一主键,但仍可能触发死锁:
- 事务范围与锁持有时间:存储过程中更新后未及时提交事务,导致排他锁长时间持有;后续查询请求共享锁,高并发下形成循环等待(如示例中3个进程形成
A→等待C的锁、C→等待B的锁、B→等待A的锁的循环)。 - 查询扫描范围扩大:生产环境主键索引存在碎片,或执行计划因数据量差异发生变化,导致查询未精准定位单行,而是扫描到其他进程持有的行,触发锁等待。
- 隔离级别影响:默认的
READ COMMITTED隔离级别下,查询会请求共享锁,若更新操作的排他锁未释放,就会引发锁竞争。
开发环境无法复现的原因
- 开发环境并发量极低,无法触发3个进程恰好形成循环等待的时序;
- 开发环境数据量小,执行计划更优,查询能精准定位单行,不会扫描到其他行;
- 开发环境的隔离级别、锁配置与生产环境不一致(如开发环境开启了快照隔离)。
解决建议
- 缩小事务范围:更新操作后立即提交事务,或确保事务仅包含必要的更新、查询步骤,减少锁持有时间;
- 开启快照隔离:启用
READ COMMITTED SNAPSHOT ISOLATION,让查询读取版本化数据,无需请求共享锁,避免锁阻塞; - 优化主键索引:定期重建/重组PK_Orders索引,消除碎片,确保查询精准定位单行;
- 验证查询语句:确认查询的过滤条件严格匹配唯一主键,避免扫描额外行;
- 调整锁提示:必要时在查询语句中添加
WITH (NOLOCK)(需权衡一致性)或WITH (ROWLOCK),强制行级锁。
死锁XML片段
<resource-list> <keylock hobtid="72057616768958464" dbid="16" objectname="Orders" indexname="PK_Orders" id="lock223c94b6980" mode="X" associatedObjectId="72057616768958464"> <owner-list> <owner id="process218b9814ca8" mode="X" /> </owner-list> <waiter-list> <waiter id="process218bb8dcca8" mode="S" requestType="wait" /> </waiter-list> </keylock> <keylock hobtid="72057616768958464" dbid="16" objectname="Orders" indexname="PK_Orders" id="lock223c94b6980" mode="X" associatedObjectId="72057616768958464"> <owner-list> <owner id="process218bb8dcca8" mode="S" requestType="wait" /> </owner-list> <waiter-list> <waiter id="process218bb829468" mode="S" requestType="wait" /> </waiter-list> </keylock> <keylock hobtid="72057616768958464" dbid="16" objectname="Orders" indexname="PK_Orders" id="lock2240f4bb680" mode="X" associatedObjectId="72057616768958464"> <owner-list> <owner id="process218bb829468" mode="X" /> </owner-list> <waiter-list> <waiter id="process218b9814ca8" mode="S" requestType="wait" /> </waiter-list> </keylock> </resource-list>
内容的提问来源于stack exchange,提问作者Jun Qian
相关产品推荐
相关产品推荐

