删除然后批量插入时的 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 死锁的主要内容,如果未能解决你的问题,请参考以下文章

SQL批量删除与批量插入

使用“一条”SQL语句完成批量插入和批量删除操作

使用“一条”SQL语句完成批量插入和批量删除操作

使用 LINQ to SQL 批量插入和复制记录

数据库中我想要批量插入数据SQL语句怎么写。

sql server有批量插入和批量更新的sql语句吗