代码之家  ›  专栏  ›  技术社区  ›  Rob West

SQL Server在选择/更新或多次选择之间死锁

  •  35
  • Rob West  · 技术社区  · 17 年前

    所有关于SQL Server死锁的文档都讨论了这样一种场景:操作1锁定资源A,然后尝试访问资源B;操作2锁定资源B,然后尝试访问资源A。

    然而,在一些繁忙的应用程序中,我经常看到select和update之间甚至多个select之间的死锁。我发现死锁跟踪输出的一些细节非常难以理解,但我真的很想了解是什么导致了两个单一操作之间的死锁。当然,如果select具有读取锁,则更新应该在获得独占锁之前等待,反之亦然?

    这在SQLServer2005上发生,我认为这并不是因为这有什么不同。

    7 回复  |  直到 17 年前
        1
  •  22
  •   David Eison    17 年前

    这可能是因为select会锁定两个不同的索引,而更新会以相反的顺序锁定相同的索引。select需要两个索引,因为第一个索引没有覆盖它需要访问的所有列;更新需要两个索引,因为如果更新索引的键列,则需要对其进行锁定。

    http://blogs.msdn.com/bartd/archive/2006/09/25/770928.aspx 有一个奇妙的解释。建议的修复措施包括添加一个包含select需要的所有列的索引,切换到快照隔离,或者显式强制select获取通常不需要的更新锁。

        2
  •  13
  •   Ben Challenor    16 年前

    我很惊讶没有人提到这个问题 WITH (UPDLOCK) 锁定提示。如果存在死锁(例如,两个select insert对并行运行),这将非常有用。

    在SQL Server中,如果使用 带(UPDLOCK)

        3
  •  6
  •   Rolf Kristensen Raúl Diego    16 年前

    我的猜测是select语句获得了一个读锁,当您使用update语句时,它需要升级到写锁。

    升级到写锁需要删除所有其他读锁(它们的select事务完成)。但是,如果另一个进程已经有了升级到写锁的绝妙想法,那么您突然有两个进程在等待对方释放读锁,这样它们就可以获得写锁。

    如果使用select for update(UPDLOCK),那么它将从一开始就获得一个写锁,这样就不会出现死锁问题。

        4
  •  5
  •   Guffa    17 年前

    单个查询之间的锁定可能发生在它们锁定单个行而不是整个表时:

        5
  •  1
  •   Pontus Gagge    17 年前

    正确阅读事务和隔离级别:有关稍微密集但相当彻底且技术中立的工作,请参阅 Principles of Transaction Processing . 它震撼了我的世界(给了我不少头痛!)。

    我不确定您遇到了什么问题,或者使用了什么隔离级别。但是考虑一下:对于所有的数据库引擎都知道,如果你在一个事务中读取,那么它如何判断你以后是否要写?高隔离级别需要在每次读取时锁定,可能是在整个表上,以防止幻象读取,因为数据可能会影响以后的写入。

    您是否希望数据库等待对您的数据进行独占锁定的时间任意长?查看您的整个隔离级别,以及您是否以隔离事务的形式不必要地运行一系列读取。要确定你能容忍多脏的书并不总是容易的,尽管。。。