【问题标题】:Two indices deadlock两个索引死锁
【发布时间】:2014-09-04 09:29:24
【问题描述】:

我在 SQL Server (Azure SQL) 中有一个表:

CREATE TABLE Commands
(
    Id int NOT NULL PRIMARY KEY,
    Body nvarchar(1000) NOT NULL,
    Priority int NOT NULL,
    DeliveryDate datetime NOT NULL,
    VisibleFrom datetime NULL,
)

表也有索引:

CREATE NONCLUSTERED INDEX IX_PriorityAndDate ON Commands (Priority DESC, DeliveryDate ASC)

然后我有两个会话。

会话 1

WITH command AS
(
    SELECT TOP(1) *
    FROM Commands q
    WHERE q.DeliveryDate <= @CurrentDate
      AND (q.VisibleFrom IS NULL OR q.VisibleFrom <= @CurrentDate)
    ORDER BY q.Priority DESC, q.DeliveryDate
)
UPDATE command SET command.VisibleFrom = DATEADD(SECOND, @LeaseTimeout, @CurrentDate)
OUTPUT inserted.Id,
       inserted.Body

第 2 场

DELETE FROM Commands WHERE Id = @Id

在某些情况下会发生死锁:

  1. 会话 1 锁定 IX_PriorityAndDate 索引(U 锁定)。
  2. 会话 2 锁定 PK_Commands 索引(X 锁定)。
  3. 会话 1 阻塞等待 PK_Commands(获取 U 锁)。
  4. 会话 2 在等待 IX_PriorityAndDate 时阻塞(获取 X 锁)。

如何解决这个死锁?

【问题讨论】:

  • 同一个命令同时被更新和删除不是逻辑bug吗?或者 IX_PriorityAndDate 上的索引访问是否读取多行?在那种情况下,为什么会有一个 UPDLOCK 提示?删除它并使用 READ COMMITTED 或快照隔离。
  • 这不是逻辑错误,这些查询是在不同的上下文中针对不同的行执行的。无论有或没有 WITH(UPDLOCK) 提示,都会发生相同的死锁。我会删除它以使问题更清楚。
  • 这些语句在什么隔离级别下运行?
  • 检查执行计划以确保索引按预期使用(即没有扫描/排序)。
  • @usr,它已提交读。

标签: sql sql-server azure-sql-database deadlock


【解决方案1】:

在我看来,您遇到了密钥查找死锁

尝试使用以下索引:

CREATE NONCLUSTERED INDEX IX_PriorityAndDate
  ON Commands (Priority DESC, DeliveryDate ASC) INCLUDE(VisibleFrom)

或者尝试创建一个新索引:

CREATE NONCLUSTERED INDEX IX_PriorityAndDate
  ON Commands(DeliveryDate, VisibleFrom) INCLUDE(Priority)

【讨论】:

    猜你喜欢
    • 2013-01-25
    • 2011-11-01
    • 2018-03-16
    • 2019-02-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 2011-01-16
    相关资源
    最近更新 更多