一个进程成为死锁受害者的原因
我有一个select过程需要很长时间才能完成,大约5到10分钟。
我目前不使用NOLOCK作为MS SQL数据库引擎的提示。
同时我们有另一个进程进行更新并插入到相同的数据库和相同的表中。
第一个过程已经开始,最近过早地结束了一个信息
SQLEXCEPTION:事务在另一个进程的锁资源上死锁,并被选为死锁受害者。
这个第一个进程在相同条件下的其他站点运行,但数据库较小,因此select语句花费的时间要短得多(大约30秒左右)。 在这些其他网站中,我没有在这些其他网站上看到死锁消息。 我也没有在最初出现问题的网站上得到这个消息,但是,我认为,随着数据库的增长,我相信我必须跨越一些门槛。 这是我的问题:
- 执行事务所花费的时间是否会使关联进程更可能被标记为死锁受害者。
- 如果我用NOLOCK提示执行select,这是否会解决问题?
- 我怀疑select语句中作为WHERE子句的一部分检查的date时间字段正在导致查询时间慢。 我可以根据这个字段创build一个索引吗? 这是可取的吗?
问题1:事务执行所花费的时间是否会使关联进程更可能被标记为死锁受害者。
不,SELECT是受害者,因为它只读取数据,因此交易的成本较低 ,因此被选为受害者:
默认情况下,数据库引擎select死循环受害者运行事务的会话,该事务回滚的成本最低 。 或者,用户可以使用
SET DEADLOCK_PRIORITY
语句在死锁情况下指定会话的优先级。 DEADLOCK_PRIORITY可设置为LOW,NORMAL或HIGH,或者可设置为范围(-10到10)内的任何整数值。
Q2。 如果我用NOLOCK提示执行select,这是否会解决问题?
不是,有几个原因:
- 你应该首先试图通过调查根本原因来消除僵局
- 脏读取是不一致的读取 。
- 指定脏读的正确方法是使用事务隔离级别
- 有一个更好的解决scheme: 读取提交的快照 。
Q3。 我怀疑select语句中作为WHERE子句的一部分检查的date时间字段正在导致查询时间慢。 我可以根据这个字段创build一个索引吗? 这是可取的吗?
大概。 死锁的原因几乎很可能是一个索引不佳的数据库。在这种狭窄的条件下,10分钟的查询是可以接受的,我对你的情况100%确定是不可接受的。
我有99%的信心,我宣称你的死锁是由一个大型表扫描引起的,与更新冲突。 首先捕获死锁图来分析原因。 您很可能不得不优化数据库的模式。 在您做任何修改之前,请阅读本主题“ devise索引”和子文章。
下面是这个特定的死锁问题是如何发生的以及它是如何解决的。 这是一个相当活跃的数据库,每天发生130K次交易。 此数据库中表中的索引最初是聚集的。 客户要求我们使索引非集群。 我们一做,僵局就开始了。 当我们将索引重新build立成簇时,死锁就停止了。
这里的答案值得一试,但你也应该检查你的代码。 具体有读Polyfun的答案在这里: 如何摆脱SQL Server 2005和C#应用程序中的死锁?
它解释了并发问题,以及如何在查询中使用“with(updlock)”可能会更正您的死锁情况 – 具体取决于您的代码正在做什么。 如果你的代码确实遵循这种模式,这可能是一个更好的解决scheme,在诉诸脏读之前,等等。