【问题标题】:UPDATE FROM deadlocks从死锁更新
【发布时间】:2017-03-31 02:25:38
【问题描述】:

我有一个 C#/.NET 应用程序,它在多个线程(即并发,6 个线程)中尝试执行以下更新:

UPDATE cWrh SET
   [Options] = cStg.[Options] -- byte array
FROM
   [wrh].[Cars] cWrh
      INNER JOIN [stg].[Cars] cStg ON
         cWrh.[Id] = cStg.[Id]
         AND cWrh.[Manufacturer_Id] = @ManufactuerId -- each thread gets different id here
         AND cWrh.[Options] <> cStg.[Options]

这是在事务中运行的一段代码。两个表都有 3+mio 记录。聚集键在 [Id] 字段上,还有一些非聚集索引。

有趣的是,我手动检查并在我的特定示例中使用 3+mio 记录 cWrh.[Options] 和 cStg.[Options] 始终相同,因此最终不需要更新。

我附上了死日志图,编辑值说 DB.wrh.Cars: Deadlock graph

是的,在这个特定的示例中,并发实际上并没有添加任何值,但这是“重置”查询;在 C# 中执行一些 [Options] 计算的“重新计算”查询、批量插入回 SQL 并稍后在并发模式下更新显着加快了处理速度。

如果可能的话,无论任务如何(简单重置与 CPU 密集型工作),我都希望坚持这种并发方法。

感谢任何关于如何解决死锁的建议。

【问题讨论】:

  • 不知道,但想知道readpast 提示是否合适?由于每个线程都有不同的@ManufactuerId,它们不应该 互相践踏(对吗?)也许还值得检查一下rowlock 是否有用。再说一次,我真的不知道,所以把这个和一粒盐放在一起。
  • 这个问题的答案可能会有所帮助。它建议使用隔离快照。 stackoverflow.com/questions/27206244/…
  • @David 你是对的,ManufacturerId 每个线程总是唯一的。我尝试了 readpas 和 rowlock 但仍然出现死锁
  • @KamranFarzami:感谢您提到隔离快照。他们似乎是正确的方法。但是,我不能一直使用它们,因为我的一些事务(除了上面提到的“重置”事务)使用临时表并在这些临时表之上创建索引;这似乎是一个已知的限制,因为无论是在本地临时表还是数据库表上,您都不能在具有快照隔离级别的事务中执行 DDL

标签: c# sql-server multithreading tsql deadlock


【解决方案1】:

正如@KamranFarzami 所建议的,@Grantly 的回答解决了我的问题。回答这个问题的重点是他们。

SNAPSHOT 的事务隔离级别可防止发生死锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-25
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    相关资源
    最近更新 更多