许多更新出现死锁错误

Posted

技术标签:

【中文标题】许多更新出现死锁错误【英文标题】:Many updates get deadlock error 【发布时间】:2017-08-07 18:31:39 【问题描述】:

使用 node.js + sequelize.js + mssql

我每 5 秒从 3 个线程更新约 30 次(一张表)。设备轮询。

获取

SequelizeDatabaseError:事务(进程 ID 57)已死锁 用另一个进程锁定资源并被选为 僵局受害者。重新运行事务。

sequelize 生成sql

sql: 

SET IDENTITY_INSERT [DeviceCurrentData] ON;

MERGE INTO [DeviceCurrentData] WITH (HOLDLOCK) AS [DeviceCurrentData_target]
USING (
    VALUES (
        9,
        N\ '28.300000\',
        \ '2017-08-07 15:26:28.000\',
        12
        )
    ) AS [DeviceCurrentData_source]([Id], [Value], [DateStamp], [DevParamId])
    ON [DeviceCurrentData_target].[Id] = [DeviceCurrentData_source].[Id]
WHEN MATCHED
    THEN
        UPDATE
        SET [DeviceCurrentData_target].[Value] = N\ '28.300000\',
            [DeviceCurrentData_target].[DateStamp] = \ '2017-08-07 15:26:28.000\',
            [DeviceCurrentData_target].[DevParamId] = 12
WHEN NOT MATCHED
    THEN
        INSERT (
            [Id],
            [Value],
            [DateStamp],
            [DevParamId]
            )
        VALUES (
            9,
            N\ '28.300000\',
            \ '2017-08-07 15:26:28.000\',
            12
            )
OUTPUT $ACTION,
    INSERTED.*;

SET IDENTITY_INSERT [DeviceCurrentData] OFF;

'

【问题讨论】:

This previous answer 可能会有所帮助。您使用HOLDLOCK 会阻止INSERTUPDATE,而使用UPDLOCK 只会阻止UPDATE。您应该跟踪该 spid 并找出失败的是 INSERT 还是 UPDATE 我写了Model.update(item, Id: item.Id),但是sequelize.js 生成了HOLDLOCK。我写了Model.upsert,也出现死锁错误 【参考方案1】:

HOLDLOCK 是表级锁。一旦发布,任何其他事务都将被阻止修改表内容,直到 HOLDLOCK 事务完成。 MERGE 不适合并发,因为它有多个阶段,在这些阶段中其他事务可能会卡住..

对于高并发,您可能应该使用 upsert。 (尝试更新,如果输出为空,则进行插入)。

此外,最好使用完整的聚集索引键一次针对单行进行更新。如果您尝试更新多行或您的过滤器未被索引覆盖,它可能会升级为更大的锁并导致死锁。

缓解死锁是一个复杂的话题。祝你好运。

【讨论】:

Model.upsert 也会出现死锁错误。带有 HOLDLOCK 的标题会自动生成,我可以更改吗?当我使用 C# 和 EntityFramework 时,我没有这个错误 是的,您可以解除锁定。假设 ID 是您的主键字段,您根本不需要为这个简单的事务添加锁。另一种选择是删除/插入。与其更新记录,不如删除它然后插入新记录。

以上是关于许多更新出现死锁错误的主要内容,如果未能解决你的问题,请参考以下文章

mysql innodb 行锁解锁后出现死锁

更新查询在同一张表上的 Sql 查询死锁

如何在单个查询完成执行之前锁定事务以防止出现死锁错误

SQL Server:在没有事务的存储过程上出现死锁受害者错误

使用 JMeter 进行负载测试时应用程序中的死锁错误

如何触发(不避免!) HttpClient 死锁