【问题标题】:SQL Select Rows from a table and update the same rowsSQL 从表中选择行并更新相同的行
【发布时间】:2011-11-01 22:59:33
【问题描述】:

我想:

  1. 从表中选择 N 行进行处理,其中 flag=0
  2. 使用这 N 行中的值在第二个表上做一些工作
  3. 更新这 N 行并设置 flag=1

我有并行的进程一起做同样的工作,我想确保所有的人都能在唯一的行上工作。我如何确保这一点?

【问题讨论】:

    标签: sql sql-server database sql-server-2005 sql-server-2008


    【解决方案1】:

    我假设您在 SQL Server 上运行(因为标签),如果不是,那么我的答案不适用。 单独锁定是不够的。如果您使用数据库记录锁定 Sql 服务器将阻止尝试访问锁定行的其他进程,实际上您一次只能处理一行。 您的解决方案是将行锁定与 READPAST 提示结合起来,以便跳过其他人锁定的行。以下是每个进程应该执行的操作:

    1. 选择下一个未锁定行进行处理并将其锁定
    2. 做好工作
    3. 更新行并结束事务

    select top 1 id, ... from TheTable with (updlock, readpast) where flag = 0

    //do the work now

    update TheTable set flag = 1 where id=<previously retrieved id>

    这里的好处是选择下一个未锁定行并锁定它的操作是原子的,因此它保证没有其他人能够选择同一行。

    【讨论】:

    • READPAST 提示可以解决问题,一篇好文章mssqltips.com/sqlservertip/1257/…
    • 在 SQL 2008 中,您可以在查询中使用带有 READPAST HINT 的 OUTPUT 子句将队列操作组合成一条语句。sqlservercentral.com/articles/Queue+processing/69653
    • @newbie 是的,您可以使用输出来锁定和检索消息,并将其标记为在单个查询中处理。但是我一直在比较单个消息处理的性能,并且与两个查询(先选择然后更新)相比没有任何收益。实际上,使用 OUTPUT 查询时,多线程吞吐量会低一些。也许在批处理中,Output 子句会更快,但对于单个消息则不然。
    【解决方案2】:

    一种方法是让主程序将段分发给子线程。

    另一种方法是锁表,获取CEIL(N/#processes) rows where flag = 0,将flag更新为2,然后释放锁。然后下一个进程将继续,因为它得到了锁,并且由于 flag = 2 它不会得到那些行。

    您有两种锁定表的方法 - 您可以锁定整个表,或者执行 SELECT ... FOR UPDATE 限制(不获取太多行)。见:SELECT FOR UPDATE with SQL Server

    将标志设置为 process_id 比将标志设置为 2 更好。然后你所要做的就是更新所有的行来分配数字,然后让这个过程开始工作,每个人只检查自己的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多