我们在生产SQL Server 2000数据库中遇到了一些非常烦人的死锁情况。
主要设置如下:
我在互联网上的几篇文章之后收集了SQL Profiler的一些初始跟踪,例如this one(忽略它指的是SQL Server 2005工具,相同的原则适用)。 从跟踪中看,它似乎是两个UPDATE查询之间的死锁。
我们采取了一些措施可能会减少问题发生的可能性:
我们也质疑我们在大多数存储过程中都有一个事务(BEGIN TRANS ... COMMIT TRANS块)。在这种情况下,我的猜测是事务隔离级别是SERIALIZABLE,对吧?那么,如果我们在源代码中指定了一个调用存储过程的事务隔离级别,那么应用哪个?
这是一个处理密集型应用程序,我们正在为数据库进行大量读取(更高百分比)和一些写入。
如果这是一个SQL Server 2005数据库,我可以使用Geoff Dalgas answer on an deadlock issue concerning Stack Overflow ,如果这甚至适用于我遇到的问题。但是,目前升级到SQL Server 2005并不是一个可行的选择。
由于这些初步尝试失败,我的问题是:你会如何离开这里?你会采取什么步骤来减少甚至避免发生死锁,或者我应该使用哪些命令/工具更好地揭露问题?
答案 0 :(得分:1)
一些评论:
存储过程中显式指定的隔离级别会覆盖调用者的隔离级别。
如果sp_getapplock在2000上可用,我会使用它:
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx
在许多情况下,可序列化的隔离级别会增加陷入僵局的可能性。
2000年的一个很好的资源:
http://www.code-magazine.com/article.aspx?quickid=0309101&page=1
Bart Duncan的一些建议也许适用:
答案 1 :(得分:0)
除了Alex的回答:
- 查看交易是否可以缩短(例如,稍后开始,提前完成,减少处理)
确定您不想失败的代码,并在其他代码中使用SET DEADLOCK PRIORITY LOW 我们已经使用了这个(SQL 2005在这里有更多选项)来确保某些代码永远不会死锁并牺牲其他代码。
如果你在事务开始时有SELECT准备一些东西,可以考虑使用HOLDLOCK(可能是UPDLOCK)来保持锁定持续时间。我们偶尔会使用它,所以请停止其他进程在此表上写入。
答案 2 :(得分:0)
我的猜测是你遇到了死锁:
为了解决这个问题,我首先检查存储过程,并确保修改语句具有所需的索引。
注意:这适用于目标表和源表(尽管NOLOCK,UPDATE的源表也会获得锁定。检查用户存储过程扫描的查询计划。与批量或批量操作不同,大多数用户查询和放大器; DML可以处理表行的一个小子集,因此不应该锁定整个表。
然后,我会检查存储过程,以确保存储过程中的所有数据访问都以一致的顺序完成(Parent - > Child通常是首选)。
答案 3 :(得分:0)
我的设置方案中出现死锁的原因是在所有索引之后。我们使用(默认生成)non clustered
索引作为表的主键。更改为clustered
索引可解决问题。