【问题标题】:Updating Identity with DELETE - OUTPUT - INSERT使用 DELETE - OUTPUT - INSERT 更新身份
【发布时间】:2014-11-13 13:29:17
【问题描述】:

我需要在一个非常具体的场景中更新一个身份列(大多数时候身份将被单独保留)。当我确实需要更新它时,我只需要给它一个新值,所以我尝试使用 DELETE + INSERT 组合。
目前我有一个看起来像这样的工作查询:

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

(这只是一个例子,真正的查询稍微复杂一些。)
一位同事提出了一个重要的观点。她问这是否不会导致死锁,因为我们正在同一张表中读写。尽管在示例中它可以正常工作(半打行),但在具有数万行的实际场景中,这可能无法正常工作。

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

我设置了一个 SQL Fiddle example
谢谢!

【问题讨论】:

  • 有趣的想法。如果这是一个索引键,那么即使它被允许(例如,对于具有序列而不是标识的列),相应的更新也可能只是作为删除 + 插入来实现。

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


【解决方案1】:

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

我对一个包含一百万行的表进行了一些测试,该表在 6 个不同的连接上并行执行了 500 万次语句。没有遇到任何死锁。

但是添加实时查询,一个带有索引和外键的表,你可能会有一个赢家。我有一个类似的声明确实导致了死锁。

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

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

因此,要完成此语句,mssql 需要为表 A 上的更新锁定、为表 B 上的插入锁定和在表 A 上共享(读取)锁定以验证表 B 对表 A 的外键。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    相关资源
    最近更新 更多