9

我在 SQL Server 中有一个表,该表由在不同会话中同时运行的存储过程同时进行 CRUD 编辑:

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

该程序的工作原理如下:

  1. 生成 GUID。
  2. 将一些记录插入上述共享表中,并使用步骤 1 中的 GUID 对其进行标记。
  3. 对步骤 2 中的所有记录执行一些更新。
  4. 选择步骤 3 中的记录作为 SP 输出。

存储过程中的每个 select / insert / update / delete 语句都有一个WHERE JobGUID = @jobGUID子句,因此该过程仅适用于它在步骤 2 中插入的记录。但是,有时当相同的存储过程在不同的连接中并行运行时,会发生死锁共享表。这是来自 SQL Server Profiler 的死锁图:

SQL Server Profiler 死锁图

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

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

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

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

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

更新:正如@Catcall建议的那样,我尝试在现有列上创建一个自然聚集的主键(不添加标识列),但仍然遇到相同的死锁(当然,这次是键锁而不是 RID 锁)。

4

2 回答 2

4

解决死锁的最佳资源(仍然)在这里:http: //blogs.msdn.com/b/bartd/archive/2006/09/09/deadlock-troubleshooting_2c00_-part-1.aspx

Pt #4 说:

通过 Database Tuning Advisor 运行涉及死锁的查询。在 Management Studio 查询窗口中执行查询,将 db 上下文更改为正确的数据库,右键单击查询文本并选择“Analyze Query in DTA”。不要跳过这一步;我们看到的超过一半的死锁问题都可以通过添加适当的索引来解决,这样其中一个查询就会运行得更快并且锁占用更少。如果 DTA 推荐索引(它会说“估计改进:%”),创建它们并监视以查看死锁是否持续存在。您可以从“操作”下拉菜单中选择“应用建议”以立即创建索引,或者将 CREATE INDEX 命令保存为脚本以在维护窗口期间创建它们。请务必分别调整每个查询。

我知道这并不能“回答”为什么必然的问题,但它确实表明添加索引可以改变执行方式,使锁占用空间更小或执行时间更快,这可以显着减少死锁的机会。

于 2012-05-24T13:51:27.287 回答
1

最近看到这个帖子,根据上面的信息希望这个帖子对你有帮助,

http://databaseusergroup.blogspot.com/2013/10/deadlocked-on-sql-server.html

于 2013-10-08T10:27:57.643 回答