【问题标题】:SQL Server 2000 DeadlockSQL Server 2000 死锁
【发布时间】:2009-06-01 22:45:47
【问题描述】:

我们在生产 SQL Server 2000 数据库中遇到了一些非常烦人的死锁情况。

主要设置如下:

  • SQL Server 2000 企业版。
  • 服务器使用 ATL OLE 数据库以 C++ 编码。
  • 正在通过存储过程访问所有数据库对象。
  • 所有 UPDATE/INSERT 存储过程都将其内部操作包装在 BEGIN TRANS ... COMMIT TRANS 块中。

我在 Internet 上的几篇文章(如 this one)之后使用 SQL Profiler 收集了一些初始跟踪(忽略它指的是 SQL Server 2005 工具,同样的原则适用)。 从跟踪来看,这似乎是两个 UPDATE 查询之间的死锁。

我们已经采取了一些措施来降低问题发生的可能性:

  • SELECT WITH (NOLOCK)。我们已将存储过程中的所有 SELECT 查询更改为使用 WITH (NOLOCK)。我们了解脏读的含义,但查询的数据并不那么重要,因为我们会进行大量自动刷新,并且在正常情况下,UI 将具有正确的值。
  • 阅读未提交。我们已将服务器代码上的事务隔离级别更改为 READ UNCOMMITED。
  • 缩小交易范围。我们缩短了事务的暂停时间,以最大限度地降低发生数据库死锁的可能性。

我们也质疑我们在大多数存储过程中都有一个事务(BEGIN TRANS ... COMMIT TRANS 块)。在这种情况下,我的猜测是事务隔离级别是 SERIALIZABLE,对吧?那么如果我们在调用存储过程的源代码中也指定了事务隔离级别,那适用哪一个呢?

这是一个处理密集型应用程序,我们对数据库进行了很多读取(更大的百分比)和一些写入操作。

如果这是一个 SQL Server 2005 数据库,我可以使用 Geoff Dalgas answer on an deadlock issue concerning Stack Overflow,如果这甚至适用于我遇到的问题。但目前升级到 SQL Server 2005 并不是一个可行的选择。

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

【问题讨论】:

    标签: sql-server sql-server-2000 deadlock


    【解决方案1】:

    几个cmets:

    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

    【讨论】:

      【解决方案2】:

      除了亚历克斯的回答:

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

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

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 您似乎只是影响了一些时间安排,巧合的是减少了相同死锁的机会。
        【解决方案4】:

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

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-11
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多