1

我们在生产 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 并不是一个可行的选择。

由于这些最初的尝试失败了,我的问题是:你将如何从这里开始?您将采取哪些步骤来减少甚至避免发生死锁,或者我应该使用哪些命令/工具来更好地暴露问题?

4

4 回答 4

1

几点评论:

  1. 在存储过程中明确指定的隔离级别会覆盖调用者的隔离级别。

  2. 如果 sp_getapplock 在 2000 上可用,我会使用它:

    http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

  3. 在许多情况下,可序列化的隔离级别会增加出现死锁的机会。

  4. 2000年的好资源:

    http://www.code-magazine.com/article.aspx?quickid=0309101&page=1

Bart Duncan 的一些建议也可能适用:

http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx

于 2009-06-01T23:14:56.693 回答
0

我的猜测是您遇到了死锁,或者:

  1. 因为您的 DML(可能更新)语句正在升级到表锁,或者
  2. 不同的存储过程在事务中访问相同的表,但顺序不同。

为了解决这个问题,我将首先检查存储过程,并确保修改语句具有它们需要的索引。

注意:这适用于目标表和源表(尽管 NOLOCK,UPDATE 的源表也会获得锁。检查查询计划以扫描用户存储过程。与批处理或批量操作不同,大多数用户查询和 DML 都适用表行的一小部分,因此不应该锁定整个表。

其次,我会检查存储过程以确保存储过程中的所有数据访问都以一致的顺序进行(通常首选父级 -> 子级)。

于 2009-06-02T05:37:20.493 回答
0

在我的设置场景中死锁的原因是所有索引。我们使用(默认生成)non clustered表的主键索引。更改为clustered索引解决了这个问题。

于 2009-07-29T07:29:56.030 回答
0

除了亚历克斯的回答:

  • 观察代码以查看是否以相同的顺序访问表。我们最近这样做了,并将代码重新排序为始终先父后子。系统变大了,代码和功能更复杂,用户更多:我们只是开始陷入死锁。

- 查看是否可以缩短事务(例如,稍后开始,更早完成,更少处理)

  • 确定您希望哪些代码不会失败并在另一个代码中使用 SET DEADLOCK PRIORITY LOW 我们已经使用了这个(SQL 2005 在这里有更多选项)来确保某些代码永远不会死锁并牺牲其他代码。

  • 如果您在事务开始时有 SELECT 来准备一些东西,请考虑 HOLDLOCK(可能是 UPDLOCK)在持续时间内保持锁定状态。我们偶尔会使用它,因此停止其他进程对该表的写入。

于 2009-06-02T04:36:01.333 回答