我们在生产 SQL Server 2000 数据库中遇到了一些非常烦人的死锁情况。
主要设置如下:
- SQL Server 2000 企业版。
- 服务器使用 ATL OLE 数据库以 C++ 编码。
- 所有数据库对象都通过存储过程进行访问。
- 所有 UPDATE/INSERT 存储过程都将其内部操作包装在 BEGIN TRANS ... COMMIT TRANS 块中。
我在网上收集了几篇类似这样的文章后,用 SQL Profiler 收集了一些初步的痕迹(忽略它是指 SQL Server 2005 工具,同样的原则适用)。从跟踪来看,这似乎是两个 UPDATE 查询之间的死锁。
我们已经采取了一些措施来降低问题发生的可能性,例如:
- 选择(不锁定)。我们已将存储过程中的所有 SELECT 查询更改为使用 WITH (NOLOCK)。我们了解脏读的含义,但查询的数据并不那么重要,因为我们进行了大量的自动刷新,并且在正常情况下 UI 将具有正确的值。
- 阅读未提交。我们已将服务器代码上的事务隔离级别更改为 READ UNCOMMITED。
- 缩小交易范围。我们减少了事务被保持的时间,以最大限度地减少发生数据库死锁的可能性。
我们还质疑我们在大多数存储过程中都有一个事务(BEGIN TRANS ... COMMIT TRANS 块)。在这种情况下,我的猜测是事务隔离级别是 SERIALIZABLE,对吧?如果我们在调用存储过程的源代码中也指定了事务隔离级别,那又会怎样呢?
这是一个处理密集型应用程序,我们在数据库中大量读取(更大的百分比)和一些写入。
如果这是一个 SQL Server 2005 数据库,我可以使用Geoff Dalgas 回答有关 Stack Overflow 的死锁问题,如果这甚至适用于我遇到的问题。但目前升级到 SQL Server 2005 并不是一个可行的选择。
由于这些最初的尝试失败了,我的问题是:你将如何从这里开始?您将采取哪些步骤来减少甚至避免发生死锁,或者我应该使用哪些命令/工具来更好地暴露问题?