同一表的 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语句的执行方式与锁以及阻塞的关系
Sql Server 优化----SQL语句的执行方式与锁以及阻塞的关系
同一台机器上的 SQL Server Express,还是外部共享的 SQL Server Standard? (对于 ASP.NET 站点)