使用DELETE更新标识 - 输出 - 插入

时间:2014-11-13 13:29:17

标签: sql-server sql-insert uniqueidentifier sql-delete database-deadlocks

我需要在非常特定的场景中更新标识列(大多数情况下,标识将保持不变)。当我确实需要更新它时,我只需要给它一个新值,因此我尝试使用DELETE + INSERT组合。
目前我有一个看起来像这样的工作查询:

DELETE Test_Id
OUTPUT DELETED.Data, 
       DELETED.Moredata 
INTO Test_id 
WHERE  Id = 13 

(这只是一个例子,真正的查询稍微复杂一点。)
一位同事提出了一个重要观点。她问我这是不会导致死锁,因为我们正在写同一张桌子。虽然在示例中它工作正常(六行),但在具有数万行的真实场景中,这可能不起作用。

这是一个真正的问题吗?如果是这样,有没有办法阻止它?

我设置了 SQL Fiddle example 谢谢!

1 个答案:

答案 0 :(得分:2)

我的第一个想法是,是的,它可以。也许它仍然有可能,但是在这个简化版本的声明中,很难遇到僵局。您正在选择可能获取行级锁定的单行,以及删除和插入所需的锁定之后非常快速地获取的事实。

我已经对一个持有一百万行的表进行了一些测试,该表在并行的6个不同连接上执行了500万次语句。没有遇到一个僵局。

但是添加reallive查询,一个包含索引和外键的表,你可能会有一个胜利者。我有一个类似的声明确实导致死锁。

我遇到了类似语句的死锁错误。

UPDATE A
SET x=0
OUTPUT INSERTED.ID, 'a' INTO B

因此,要完成此语句,mssql需要为表A上的更新锁定,表B上的插入锁定和表A上的共享(读取)锁定以验证外键表B必须到表A. / p>

最后但并非最不重要的是,mssql认为在这个特定查询上使用并行是明智的,导致语句自身死锁。要解决这个问题,我只需在语句中设置“MAXDOP 1”查询提示,以防止出现并行性。

然而,没有明确的答案可以防止死锁。正如他们对mssql说的那样,这取决于它。您可以使用TABLOCKX表提示进行独占。这样可以防止死锁,但由于其他原因,这可能是不可取的。