如何在RDBMS中检测并报告死锁?


8

面试时我被问到了这篇论文类型的问题,但没有得到这份工作。完整的问题如下:

如何在RDBMS中检测并报告死锁?在检测和预防场景中,交易所有者和应用程序开发人员分别负责什么?

Answers:


13

在SQL Server中,有一个单独的线程定期(默认为5秒,如果刚刚检测到死锁,则间隔更短)检查任何周期的等待列表。即,它标识线程正在等待的资源,然后找到该资源的所有者,然后递归查找该线程又在等待哪个资源,从而标识正在等待彼此的资源。

如果发现死锁,则使用以下算法选择杀死受害者:

  1. 标识不可杀死的线程(例如,回滚事务的线程不可杀死)。
  2. 查找具有最低死锁优先级的线程。
  3. 选择一个最便宜的回滚对象,即到目前为止做得最少的一个。

您可以在此处找到有关SQL Server死锁检测的更多信息:http : //msdn.microsoft.com/zh-cn/library/ms178104.aspx



事务所有者/应用程序开发人员负责最小化死锁发生的风险,并为此做他们应该:

  1. 确保交易时间尽可能短。例如,在开始交易并等待用户输入后不显示登录表单,而是收集所需的所有信息,然后运行交易。
  2. 使用最低的隔离级别,例如,当您只想向用户临时显示一些值时,不要设置可序列化。请注意,设置正确的隔离级别本身就是一门科学,并且超出了此答案的范围。
  3. 如果您是死锁的受害者,即收到错误号1205,则对用户透明地重新运行事务。由于另一笔竞争的交易现在有望获得正在等待并完成的资源,因此再次遇到同样的僵局是不可能的。

4.在整个应用程序中一致地获取资源并以相同顺序执行更新/删除/插入模式。
ErikE'2

3
@ErikE“在整个应用程序中始终以相同的顺序执行更新/删除/插入模式”通常是不可能/可行的,尽管这种可疑的建议在网络上非常流行。此处的详细信息:sqlblog.com/blogs/alexander_kuznetsov/archive/2010/01/15/…–
AK

1
好点。但我仍然认为,这样做是值得的,只要不幻想它总是可能或总是可以解决问题。父/子事情很有趣,级联删除或首先在父行上获取更新锁如何?如果没有合并就合并,为什么不保持一致呢?我个人删除->更新->插入。
ErikE 2012年

1
@AlexKuznetsov:这不是求解器的子弹,但不应该被解雇。我通过以下方式减少了(但没有消除)死锁:通过对每天都会发生死锁或7次的频繁运行的代码进行静态分析,我建议采用“过早的优化”,等等
gbn 2012年

我不同意建议3。当我们在死锁后重试时,我们很可能会覆盖其他进程的更改。我们需要意识到,很可能有人修改了我们要修改的数据。尤其是如果所有读取器都在快照隔离下运行,那么读取器将不会陷入死锁,这意味着死锁中涉及的所有各方都是写入者,被修改或试图修改同一数据。如果我们只是捕获异常并自动重试,则可以覆盖其他人的更改。这被称为丢失更新,这通常是错误的。
AK
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.