删除然后批量插入时的 SQL 死锁
Posted
技术标签:
【中文标题】删除然后批量插入时的 SQL 死锁【英文标题】:SQL deadlock on delete then bulk insert 【发布时间】:2010-03-22 21:45:27 【问题描述】:我遇到了无法解决的 SQL Server 死锁问题。
基本上,我有大量并发连接(来自许多机器)正在执行事务,它们首先删除一系列条目,然后使用批量插入在同一范围内重新插入条目。
本质上,交易是这样的
BEGIN TRANSACTION T1
DELETE FROM [TableName] WITH( XLOCK HOLDLOCK ) WHERE [Id]=@Id AND [SubId]=@SubId
INSERT BULK [TableName] (
[Id] Int
, [SubId] Int
, [Text] VarChar(max) COLLATE SQL_Latin1_General_CP1_CI_AS
) WITH(CHECK_CONSTRAINTS, FIRE_TRIGGERS)
COMMIT TRANSACTION T1
批量插入仅在同一事务中插入与删除的Id和SubId匹配的项目。此外,这些 Id 和 SubId 条目不应重叠。
当我有足够的这种形式的并发事务时,我开始看到这些语句之间出现大量死锁。
我添加了锁定提示 XLOCK HOLDLOCK 来尝试处理该问题,但它们似乎没有帮助。
此错误的规范死锁图显示:
连接 1:
在 PK_TableName 上保持 RangeX-X 在表上持有 IX 页锁 在表上请求 X 页锁定连接 2:
在表上持有 IX 页锁定 在桌子上请求 RangeX-X 锁定我需要做些什么来确保不会发生这些死锁。
我一直在阅读有关 RangeX-X 锁的一些信息,但我不确定我是否完全理解这些锁的情况。除了在此处锁定整个表格之外,我还有其他选择吗?
【问题讨论】:
【参考方案1】:按照 Sam Saffron 的回答:
如果 @ID7@SubID 不同,请考虑 READPAST 提示跳过任何持有的锁 考虑 SERIALIZABLE 并删除 XLOCK、HOLDLOCK 为批量插入使用单独的临时表,然后从中复制【讨论】:
【参考方案2】:如果没有索引/表大小等列表,很难给你一个准确的答案,但是请记住,SQL 不能在同一个实例中获取多个锁。它会一次抓住一个锁,如果另一个连接已经持有锁并且它持有第一个事务需要的锁,那么你就会陷入死锁。
在这种特殊情况下,您可以做一些事情:
-
确保 (Id, SubId) 上有一个索引,这样 SQL 将能够为正在删除的数据获取单个范围锁。
如果死锁变得罕见,请重试死锁。
您可以用大锤来解决这个问题,并使用永远不会死锁的 TABLOCKX
使用跟踪标志 1204 http://support.microsoft.com/kb/832524 获得准确的死锁分析(关于实际死锁的信息越多,解决问题就越容易)
【讨论】:
以上是关于删除然后批量插入时的 SQL 死锁的主要内容,如果未能解决你的问题,请参考以下文章