请求分析SQL Server死锁XML文件内容
咱们来好好拆解下这个SQL Server死锁的XML日志,把问题掰扯清楚:
死锁核心概况
首先看受害者:**进程processa9f6f73c28**被SQL Server终止以打破死锁,它当时正尝试执行删除操作,等待一个排他锁(X)。
参与死锁的三个进程详情
进程1(受害者):processa9f6f73c28
- 执行路径:调用存储过程
[model].[RelationshipPair_DeleteByRelationshipIds],核心SQL是:DELETE RP FROM [model].RelationshipPair RP INNER JOIN @RelationshipIdTable RIT ON RP.RelationshipId = RIT.EntityI - 等待状态:需要对键资源
KEY: 5:72057594060013568 (bd1a413b4dd8)加排他锁(X),已等待1759ms - 基础信息:事务ID
19463226,隔离级别为默认的READ COMMITTED,来自.Net SqlClient Data Provider客户端
进程2:processa9f9857088
- 执行路径:调用
[model].[ModelItem_Relationship_Create]→ 触发[model].[ModelItem_Generic_Create],核心是插入操作:INSERT INTO [model].[ModelItem] ( [MetamodelItemId], [ModelItemCategoryId] ) OUTPUT [inserted].[ModelItemId], [inserted].[MetamodelItemId] INTO @ModelItemIdsByMetamodelId SELECT EntityId, @ModelItemCategoryId FROM @MetamodelItemIdTabl - 等待状态:需要对键资源
KEY: 5:72057594060013568 (3f1e49aa6519)加共享范围锁(RangeS-S),已等待2779ms - 基础信息:事务ID
19414353,同样是READ COMMITTED隔离级别,和受害者来自同一客户端主机
进程3:processa9fb862108
- 执行路径:调用
[model].[ModelItem_Generic_Delete](XML内容被截断,但能看出来是删除操作) - 等待状态:需要对键资源
KEY: 5:72057594060013568 (bd1a413b4dd8)加共享范围锁(RangeS-S),已等待40ms - 基础信息:事务ID
19385479,READ COMMITTED隔离级别,同一客户端主机
死锁根源分析
三个进程都在争抢同一个索引对应的键资源(72057594060013568是数据库5里的某个索引ID,大概率属于RelationshipPair或ModelItem表):
- 进程1(删除)要拿排他锁,但目标键已经被进程3持有了共享范围锁
- 进程3又在等进程1释放锁,同时进程2在等另一个键的锁,形成了循环等待的死锁链
- 所有进程都来自同一客户端实例,说明是服务内部的并发操作冲突导致的
初步解决建议
- 缩短事务时长:检查存储过程里有没有没必要的延迟操作,把大事务拆小,减少锁的持有时间
- 优化索引:看看涉及的两张表的索引是不是合理,让删除/插入更快,锁的持有时间更短
- 调整隔离级别:如果业务允许,开启
READ COMMITTED SNAPSHOT,用快照读避免阻塞;或者改写查询减少范围锁的产生 - 应用层控制:对操作相同数据的请求做排队处理,避免同时执行冲突的删插操作
内容的提问来源于stack exchange,提问作者Umair




