可以添加主键标识列来解决死锁问题吗?

时间:2012-05-24 12:15:56

标签: sql-server concurrency primary-key deadlock

我在SQL服务器中有一个表,它由在不同会话中同时运行的存储过程同时进行CRUD:

|----------------|---------|
| <some columns> | JobGUID |
|----------------|---------|

该程序的工作原理如下:

  1. 生成GUID。
  2. 将一些记录插入上述共享表中,并使用步骤1中的GUID标记它们。
  3. 对步骤2中的所有记录执行一些更新。
  4. 从步骤3中选择记录为SP输出。
  5. 存储过程中的每个select / insert / update / delete语句都有一个WHERE JobGUID = @jobGUID子句,因此该过程仅适用于它在步骤2中插入的记录。但是,有时当相同的存储过程运行时在不同的连接中并行,共享表上会发生死锁。以下是SQL Server Profiler的死锁图:

    SQL Server Profiler Deadlock Graph

    不会发生锁定升级。我尝试将(UPDLOCK, ROWLOCK)锁定提示添加到所有DML语句和/或在事务中包装过程的主体并使用不同的隔离级别,但它没有帮助。共享表上的RID锁定仍然相同。

    之后我发现共享表没有主键/标识列。一旦我添加它,死锁似乎已经消失了:

    alter table <SharedTable> add ID int not null identity(1, 1) primary key clustered
    

    当我删除主键列时,死锁又回来了。当我把它添加回来时,我再也无法重现死锁了。

    所以,问题是,主键身份列真的能够解决死锁还是巧合?

    更新:@Catcall所示,我尝试在现有列上创建一个自然的聚簇主键(不添加标识列),但仍然遇到了同样的死锁(当然,这次它是一个钥匙锁而不是RID锁。​​)

2 个答案:

答案 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