SQL计数器增量并发问题 - 选择/更新问题

时间:2015-10-16 19:47:26

标签: sql multithreading database-concurrency

这更像是一个知识共享帖子。

最近在我的一个项目中,我遇到了一个非常常见的问题,但在面对它之前从未真正考虑过这个问题。 有很多可用的解决方案,但不知怎的,我找不到我想要的那个,我将在这篇文章中分享。我相信你们中的许多人已经知道了下面的解决方案,但对于那些不这样做的人来说,这绝对可以成为一个救生员。 : - )

问题:

最近,我正在开发一项Windows服务。该服务应该将一些记录插入到一​​个长期存在并被其他几个旧服务使用的表中。有一个列(比如说“ID”),它保存一个整数值。写入(可能是几年前)以使Integer插入此表的逻辑如下所述:

逻辑:

  1. 从表中读取一个值(比如表1 - 名称/值对),
  2. 将其增加1
  3. 更新值
  4. 最后获得新值[/ highlight]。
  5. 代码

    SELECT @value = [Value] from [dbo].[Table1] WHERE [Name] = @Name;
    UPDATE [dbo].[ Table1] SET [Value] = @value +1  WHERE [Name] = @Name;
    SELECT @value = @value+1;
    

    使用的技术存在重大并发问题。

    1. 多线程读取相同的值
    2. 死锁问题
    3. 解决此类问题的最佳方法是什么?考虑到这一点在许多不同的应用程序/服务中都有提及?

1 个答案:

答案 0 :(得分:2)

决议

显而易见的想法是摆脱这件事并重写这一点。但有时候,特别是当您在这样的区域工作时,某些逻辑,表格,代码已经被其他几个程序引用,这不是一个简单的调用。

我的目标是攻击问题的根源并摆脱它。如果我能做到这一点,那么应该没有真正的影响。 proc的输出是相同的,所以对外界来说没有任何实际改变。 : - )

因此,我对上述语句进行了一些小的调整,以确保每个线程都更新值并读取更新的值。没有更多的冲突,没有更多的脏读。

更新代码

DECLARE @table table(
    Value int NOT NULL
);

-- Update the value and output the same into a local table variable
UPDATE [dbo].[Table1] SET [Value] = [Value] + 1  OUTPUT inserted.[Value] INTO @table
WHERE [Name] = @Name

-- Now read the value from the local table variable
SELECT Value FROM @table;

有关输出子句检查https://msdn.microsoft.com/en-us/library/ms177564(v=sql.90).aspx

的更多信息

我用parallel.foreach(20,000次)进行了一些测试。我的测试表有两个条目 -

  1. Name = First和Value = 1 - 20,000次更新后,该值应为20,001
  2. Name = Second,Value = 100 - 20,000次更新后,该值应为20,100
  3. 如果您检查附件,您会发现数字的差异。

    TestResults

    死锁问题难以重现,但多个线程读取相同值的问题在测试结果中清晰可见。

    对此我们表示欢迎。

    正如我之前所说,很多人已经知道这个解决方案,但对于那些不这样做的人来说,这绝对可以节省一些时间。 : - )