我在SQL服务器中有一个表,它由在不同会话中同时运行的存储过程同时进行CRUD:
|----------------|---------|
| <some columns> | JobGUID |
|----------------|---------|
该程序的工作原理如下:
存储过程中的每个select / insert / update / delete语句都有一个WHERE JobGUID = @jobGUID
子句,因此该过程仅适用于它在步骤2中插入的记录。但是,有时当相同的存储过程运行时在不同的连接中并行,共享表上会发生死锁。以下是SQL Server Profiler的死锁图:
不会发生锁定升级。我尝试将(UPDLOCK, ROWLOCK)
锁定提示添加到所有DML语句和/或在事务中包装过程的主体并使用不同的隔离级别,但它没有帮助。共享表上的RID锁定仍然相同。
之后我发现共享表没有主键/标识列。一旦我添加它,死锁似乎已经消失了:
alter table <SharedTable> add ID int not null identity(1, 1) primary key clustered
当我删除主键列时,死锁又回来了。当我把它添加回来时,我再也无法重现死锁了。
所以,问题是,主键身份列真的能够解决死锁还是巧合?
更新:如@Catcall所示,我尝试在现有列上创建一个自然的聚簇主键(不添加标识列),但仍然遇到了同样的死锁(当然,这次它是一个钥匙锁而不是RID锁。)
答案 0 :(得分:4)
死锁解决的最佳资源(仍然)在这里:http://blogs.msdn.com/b/bartd/archive/2006/09/09/deadlock-troubleshooting_2c00_-part-1.aspx。
Pt#4说:
通过数据库调优运行死锁中涉及的查询 顾问。在Management Studio查询窗口中跳过查询,进行更改 db上下文到正确的数据库,右键单击查询文本和 选择“在DTA中分析查询”。不要跳过这一步;超过一半 我们看到的死锁问题只需添加一个即可解决 适当的索引,以便其中一个查询运行得更快 锁定占地面积较小。如果DTA建议索引(它会说 “估计改进:%”),创建并监控 看看死锁是否仍然存在。您可以选择“应用建议” 从Action下拉菜单中立即创建索引,或 将CREATE INDEX命令保存为脚本以在a期间创建它们 维护窗口。请务必分别调整每个查询。
我知道这并没有“回答”问题为什么必然,但它确实表明添加索引可以改变执行方式,使锁占用空间更小或执行时间更快,这可以显着降低死锁。
答案 1 :(得分:1)
最近我看过这篇帖子,根据以上信息,我希望这篇文章对你有帮助,
http://databaseusergroup.blogspot.com/2013/10/deadlocked-on-sql-server.html