进程成为死锁受害者的原因


105

我有一个选择过程,需要很长时间才能完成,大约需要5到10分钟。
我目前不使用NOLOCK作为对MS SQL数据库引擎的提示。
同时,我们还有另一个过程进行更新,并将其插入相同的数据库和相同的表中。
第一个过程已经开始,最近以消息提前结束

SQLEXCEPTION:事务已在另一个进程的锁定资源上死锁,并且已被选择为死锁受害者。

该第一个过程在其他条件相同的站点上运行,但数据库较小,因此,所选择的select语句花费的时间短得多(大约30秒左右)。在这些其他站点中,我没有在这些其他站点中收到死锁消息。我也没有在最初出现问题的站点上收到此消息,但是,我认为,随着数据库的增长,我相信我一定已经超过了一些门槛。这是我的问题:

  1. 事务执行所花费的时间是否会使关联的进程更有可能被标记为死锁受害者。
  2. 如果我使用NOLOCK提示执行选择,是否可以解决问题?
  3. 我怀疑在select语句中作为WHERE子句的一部分检查的datetime字段会导致查找时间变慢。我可以基于此字段创建索引吗?这是明智的吗?

关于问题1的部分答案:不要将死锁与超时混淆。如果您超时,则完成一项交易所需的时间可能会导致另一笔异常终止。另外,了解您正在死锁的资源(它是索引还是表?)也很有用。
NealB 2011年

1
SET DEADLOCK_PRIORITY HIGH ALTER DATABASE数据库名SET MULTI_USER;
gstackoverflow

Answers:


128

Q1:事务执行所花费的时间是否会使关联的进程更有可能被标记为死锁受害者。

不会。SELECT是受害者,因为它仅读取数据,因此事务具有较低的关联成本,因此被选为受害者:

默认情况下,数据库引擎选择运行事务的会话作为死锁受害者,该会话的回滚成本最低。或者,用户可以使用该SET DEADLOCK_PRIORITY语句在死锁情况下指定会话的优先级。可以将DEADLOCK_PRIORITY设置为LOW,NORMAL或HIGH,或者可以将其设置为(-10到10)范围内的任何整数值。

Q2。如果我使用NOLOCK提示执行选择,是否可以解决问题?

否。原因如下:

Q3。我怀疑在select语句中作为WHERE子句的一部分检查的datetime字段会导致查找时间变慢。我可以基于此字段创建索引吗?这是明智的吗?

大概。僵局的原因是几乎很可能是一个索引不佳database.10分钟查询是在这样的条件下窄接受,那我在你的情况下,100%肯定是不能接受的。

拥有99%的置信度,我声明大表扫描与更新冲突掩盖了您的僵局。首先捕获死锁图以分析原因。您很可能必须优化数据库的架构。在进行任何修改之前,请阅读本主题设计索引和子文章。


感谢您的详尽回答。我想我仍然有一个问题。为什么我只能在一个环境而不是另一个环境中遇到僵局。即使软件相同。您的答案表明,运行Select查询的时间长度没有任何区别,事实是它本身就是Select查询,这导致了过程失败。但是,为什么仅当选择查询需要很长时间才能执行?
艾略特

4
查询的时间长度对选择死锁受害者没有影响。造成死锁的原因至少有两个,这确实有所不同:1)简单概率。查询时间越长,就越有可能使并发更新重叠并陷入死锁。2)较大的表可能使用完全不同的查询计划,该计划容易出现死锁。
Remus Rusanu

12

这是此特定死锁问题的实际发生方式以及如何实际解决。这是一个相当活跃的数据库,每天发生13万笔交易。该数据库中表的索引最初是群集的。客户要求我们使索引不成簇。一旦我们做到了,僵局就开始了。当我们将索引重新建立为集群索引时,僵局停止了。


34
有人可以解释为什么吗?(
不可思议的

1
:这家伙解释了它在自己的岗位 mssqltips.com/sqlservertip/2517/...
siga0984

6

这里的答案值得一试,但是您也应该查看代码。具体请阅读以下Polyfun的答案: 如何摆脱SQL Server 2005和C#应用程序中的死锁?

它解释了并发性问题,以及查询中“ with(updlock)”的使用如何纠正您的死锁情况-确实取决于代码在做什么。如果您的代码确实遵循此模式,则在进行脏读等操作之前,这可能是一个更好的解决方法。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.