SQL Server里如何处理死锁

在今天的文章里,我想谈下SQL Server里如何处理死锁。当2个查询彼此等待时会发生死锁,没有一个查询能够继续它们的操做。首先我想给你大体讲下SQL Server如何处理死锁。最后我会展现下SQL Sever里特定的死锁类型,还有你如何避免和解决它们。sql

死锁处理

死锁的好处是SQL Server自动检测并解决它们。为了解决死锁,SQL Server须要回滚2个事务中最便宜的那个。在SQL Server上下文中,最便宜的事务是写入事务日志更少字节的那个。并发

SQL Server在后台进程中实现死锁检测称为死锁监控(Deadlock Monitor)。这个后台进程每5秒钟运行一次,为死锁检查当前锁定状况。在最坏的状况中,所以一个死锁不该该超过5秒。这个查询会回滚并收到1205错误号。死锁的好事是你能够完整从错误状况下还原,不须要用户的任何干预。一个聪明的开发者必须按下列步骤来从死锁中恢复:spa

  • 当异常抛出时,检查1205错误号
  • 暂时中止程序,给其余查询时间来完成它的事务并释放它得到的锁
  • 从新提交查询,即被SQL Server回滚的。

从新提交查询后,这个查询应该继续执行,没有任何问题,由于其它查询已经完成它的事务。固然你应该保持再次发生死锁的跟踪,这样的话,你不用反复重试你的事务。线程

你能够用多种方法来故障排除死锁。SQL Server Profiler提供Deadlock Graph事件,一旦死锁检测到就会发生。若是你在SQL Server 2008或更高,你可使用故障排除来故障排除死锁场景。扩展事件提供你system_health事件会话,它跟踪自SQL Server上次重启后发生过的死锁。还有启用1222跟踪标记,SQL Server会把死锁信息写入错误日志。设计

死锁类型

在SQL Server里会发生各类类型的死锁。在这一部分我想进一步谈下最多见的几个。日志

几乎每一个SQL Server我看到最典型的的死锁是著名的书签查找死锁,当你有同时对汇集和非汇集索引读写活动时发生。它基本上是由于很差的索引设计形成的。在我做平常SQL Server的故障排除重,我能够说全部的死锁,至少有90%能够经过更好的索引设计来解决。书签查找死锁能够经过提供覆盖非汇集索引轻松解决。server

另外一个常见的死锁是所谓的循环死锁(Cycle Deadlock),这里你的每一个查询用不一样的顺序访问表。为了不这个特定的死锁,你要确保每一个查询用一样的顺序访问表。在SQL Server里会发生的最有意思的死锁是所谓的内部并行死锁(Intra-Parallelism Deadlock),这里平行的运算符在各自的线程内部死锁。下图展现了一个典型死锁图。blog

图片自己就是一个艺术品,它因触发SQL Server里的BUG而发生。遗憾的是,这个BUG不会被微软修正,由于它引入回归的可能性。所以你要确保引发这个死锁的查询,要在SQL Server里单线程运行。你能够经过多个选项来实现单线程执行:索引

  • 在你的索引策略上下功夫,这样的话查询的花费会在当前并行阈值下(默认为5)
  • 使用MAXDOP 1查询提示,来提示SQL Server以单线程运行你的问题查询

另外一个死锁的特效疗法是启用乐观并发,尤为是提交读快照隔离(Read Committed Snapshot Isolation (RCSI)),他对你的程序是彻底透明的。使用乐观并发,共享锁消失,这意味着在SQL Server里你能够避免大量的典型锁。进程

小结

死锁是SQL Server经过回滚最便宜的事务自动处理。然而你要尽量小的确保死锁,由于每一个回滚的死锁都会给你的终端用户带来很差的影响。死锁能够经过好的索引策略来避免,另外使用乐观并发也是应付它们的特效药。

感谢关注!

原文连接

 https://www.sqlpassion.at/archive/2017/02/20/how-to-handle-deadlocks-in-sql-server

相关文章
相关标签/搜索