同一表的 UPDATE 上的 SQL Server 死锁

Posted

技术标签:

【中文标题】同一表的 UPDATE 上的 SQL Server 死锁【英文标题】:SQL Server Deadlock on UPDATE for the same table 【发布时间】:2014-02-13 12:48:19 【问题描述】:

我有3个存储过程(简化,请尽量忽略我为什么要更新表两次以及为什么调用SP两次):

CREATE SP1 AS
BEGIN TRANSACTION

   -- Updated twice
   UPDATE Customers SET Name = 'something' Where Id = 1 OUTPUT INSERTED.*
   UPDATE Customers SET Name = 'something'

   COMMIT TRANSACTION;
END

CREATE SP2 AS
BEGIN TRANSACTION
   UPDATE Customers SET Name = 'anothername'
   COMMIT TRANSACTION;
END

CREATE SP3 AS
BEGIN TRANSACTION

    -- Called twice 
    EXEC SP2
    EXEC SP2

    COMMIT TRANSACTION;
END 

问题是我从 sql server 遇到了死锁。它说 SP1 和 SP3 都在等待客户表资源。是否有意义?可能是因为 SP2 中的内部事务?或者也许使用 OUTPUT 语句...?

锁是客户PK上的钥匙锁。每个等待的 SP 请求的锁定模式是 U,所有者是 X(我猜是另一个对象)。

更多细节: 1. 这些在不同的进程上被同一个用户多次调用。 2. 语句被调用两次只是为了示例。 3. 在我的实际代码中,客户实际上被称为“待处理指令”。每个听众(实际上是计算机)每分钟对指令表进行一次采样。 4. 第一个更新查询首先获取所有待处理的指令,第二个更新整个表的状态为已完成,只是为了确保没有一个处于待处理模式。 5. SP3 调用 SP2 两次,因为它更新了 2 个专有指令行,这种情况每天发生一次。

非常感谢!!

【问题讨论】:

您总是更新完整的客户表还是只更新一个子集?这些存储过程是被称为线性的还是来自不同的用户多次?请原谅我问,但你为什么要更新它们两次? :) 添加了更多有问题的信息,请查看。第一次更新是 1 行,第二次是整个表。多次从不同的用户调用。 【参考方案1】:

你为什么对此感到惊讶?你已经写了一个死锁的书柜并击中它。

第一个更新查询首先获取所有待处理的指令,第二个更新整个表的状态为完成。

是的,这会死锁。两个并发调用将找到不同的“待处理”指令(因为可以在其间插入新的“待处理”指令)。然后他们将继续尝试更新整个表并相互阻塞,死锁。这是时间线:

    表包含customer:1,待处理 T1(运行 SP1 的第一次更新)更新表并修改 customer:1 T2 插入一条新记录,customer:2,待处理 T3(运行 SP1 的第一次更新)更新表并修改 customer:2 T1(运行 SP1 的第二次更新)尝试更新所有表,被 T3 阻止 T3(运行 SP1 的第二次更新)尝试更新所有表,被 T1 阻止。 死锁

不过我有一个好消息:僵局是您可以获得的最佳结果。更糟糕的结果是您的逻辑错过了“待定”客户(这种情况会更频繁地发生)。简单地说,您的 SP1 将错误地将在第一次更新后插入的任何新的“待处理”客户标记为“已处理”,而实际上它只是被跳过了。这是时间线:

    表包含customer:1,待处理 T1(运行 SP1 的第一次更新)更新表并修改 customer:1 T2 插入一条新记录 customer:2,待处理 T1(运行 SP1 的第二次更新)尝试更新整个表。 customer:2 处于挂起状态,并在未实际处理的情况下被重置(不是 i SP1 的结果集)。 您的商家丢失了更新。

所以我建议回到绘图板并正确设计SP1。例如,我建议 SP1 应该只在第二个语句上更新它在第一个语句上更新的内容。发布带有适当 DDL 的真实代码,将有助于获得有用的解决方案。

【讨论】:

顺便说一句,你的答案不准确,因为我没有在那里做任何插入。 我认为这与首先锁定表然后PK,而不是插入有关。不过我不确定……

以上是关于同一表的 UPDATE 上的 SQL Server 死锁的主要内容,如果未能解决你的问题,请参考以下文章

通过比较sql server中同一张表的每条记录返回重复

SQL Server - 同一列上的多个 PIVOT

Sql Server 优化----SQL语句的执行方式与锁以及阻塞的关系

Sql Server 优化----SQL语句的执行方式与锁以及阻塞的关系

同一台机器上的 SQL Server Express,还是外部共享的 SQL Server Standard? (对于 ASP.NET 站点)

在 SQL Server 2005 中将列标识上的标识设置为另一个表的列