Sql Merge 语句在多线程时导致重复

标签 sql sql-server multithreading

我有一个基于键执行更新插入的合并语句。 (为简单起见,我们将其称为 RefId)。这是为了确保表是唯一的 RefId .
但是,在生产中,我们有多个服务器使用此存储过程插入到该表中,如果两台服务器以非常接近的间隔使用相同的 RefId 插入,则会发生重复(即 2 次插入)而不是 1 次插入和更新。我相信这是因为,SQL 服务器锁定了新插入的行,而另一个称为存储过程的并行无法检测到它的存在。 MERGE 语句不支持 NoLock,因此我看不到明显的解决方法。
我已经使用多个线程(而不是服务器)模拟了并行插入,并且在这种情况下偶尔也会发生重复。除了对数据库强制执行唯一约束(我无法控制的原因)之外,还有什么方法可以让我的 upsert 在并发情况下按预期工作?

这是存储的过程(当插入更新以合理的时间差进行时它可以正常工作,但在并行情况下会失败)

WITH UniqueData AS 
    ( SELECT * FROM 
      ( SELECT *, rank() over ( PARTITION BY RefId ) AS UniqueRank 
          FROM @Data  
      ) AS Ranked WHERE UniqueRank=1 
    )
  MERGE MyTable AS destination
  USING UniqueData AS source
  ON ( destination.RefId = source.RefId)
  WHEN NOT MATCHED THEN
    INSERT (RefId, Miles,UpdateUTC)
    VALUES( source.RefId, source.Miles, getutcdate())
  WHEN MATCHED THEN
    UPDATE SET 
               destination.Miles = ISNULL(source.Miles , destination.Miles ),
               destination.UpdateUTC = getutcdate()   

最佳答案

您可以使用 WITH (HOLDLOCK)

...
 MERGE MyTable WITH (HOLDLOCK) AS destination
...

您可以在此处阅读详细信息:
http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx

关于Sql Merge 语句在多线程时导致重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23509592/

相关文章:

sql - 权限表的性能问题

sql - 从同一个表的组中减去值

python : print output of each thread to seperate file

java - 如何高效地同时运行 10-15 个线程

java - criteria api 如何向列添加引号?

sql - 需要在 SQL 查询中替换 union

mysql - 比较两列以获得不相同的数据

javascript - 防止sequelize软删除在其他地方引用的行

sql-server - 在动态sql中如何检查日期

c++ - 将 std::vector 与 std::thread 一起使用