【问题标题】:SQL Server 2008 - Select disjunct rowsSQL Server 2008 - 选择分离行
【发布时间】:2011-06-03 10:41:57
【问题描述】:

我有两个并发进程,我有两个查询,例如:

select top 10 * into #tmp_member
from member
where status = 0
order by member_id

然后

update member
set process_status = 1
from member inner join #tmp_member m
on member.member_id=m.member_id

我希望每个进程选择不同的行,因此如果第一个进程已经选择了一行,则不要在第二个进程的结果列表中使用该行。

我必须玩锁吗? UPDLOCK、ROWLOCK、READPAST 提示可能吗?还是有更直接的解决方案?

感谢您的帮助,

干杯,

b

【问题讨论】:

  • 目前您的第二个查询只会更新您的第一个查询插入到临时表中的行。您想更改第二个查询,使其不使用第一个查询结果?
  • 不,他需要两条语句:选择条目,然后更新所选条目。但是,有两个进程在执行这两个调用。现在的问题是进程 2 可能选择与进程 1 相同的 10 个条目,因为选择和更新不是原子操作。他不希望进程 2 再次更新相同的条目。
  • 没错,感谢您的澄清!

标签: sql sql-server-2008 locking


【解决方案1】:

你需要提示。

在这里查看我的答案:SQL Server Process Queue Race Condition

但是,您可以使用OUTPUT clause 将上述查询缩短为一条语句。否则你也需要一个事务(假设每个进程一个接一个地执行上面的 2 个语句)

update m
set process_status = 1
OUTPUT Inserted.member_id
from
  (
  SELECT top 10
      process_status, member_id
    from member WITH (ROWLOCK, READPAST, UPDLOCK)
    where status = 0
    order by member_id
  ) m

总结:如果你想要多个进程

  1. select 10 rows where status = 0
  2. set process_status = 1
  3. 以安全、并发的方式返回结果集

...然后使用此代码。

【讨论】:

  • 我找到了类似的解决方案,但我没有使用 ROWLOCK。没有它似乎可以工作。为什么必须同时使用 ROWLOCK 和 UPDLOCK?
  • ROWLOCK = 粒度也就是只锁定行(而不是页面等)。 UPDLOCK = 隔离,需要确保同一行没有被 2 个不同的进程选择。 ROWLOCK 仍将允许 2 个不同的进程选择同一行。 READPAST 跳过被另一个进程锁定的行。您需要所有三个提示...
  • 我认为我理解 READPAST 和 UPDLOCK。那么 ROWLOCK 会减轻 UPDLOCK 的锁定级别吗?这样它就不会锁定页面而只会锁定行?这意味着它在没有 ROWLOCK 的情况下更强大,但仍然有效。我还缺少什么吗? :)
  • 是的,你错过了一些东西...... UPDLOCK 影响并发,ROWLOCK 影响粒度。两者都不影响对方。 ROWLOCK 停止“对整个表的锁定升级*,无论是读取、独占等。UPDLOCK 确定对锁定的任何内容(行、页、表等)的隔离
  • 好的,我想我现在明白了。也感谢您的解决方案和答案!
【解决方案2】:

问题在于您的选择/更新不是原子的 - 第二个进程可能会在第一个进程已选择和更新之前选择前 10 个项目。

您可以在 UPDATE 语句中使用 OUTPUT 子句来使其具有原子性。有关详细信息,请参阅文档,但基本上您可以编写如下内容:

DECLARE @MyTableVar table(member_ID INT)
UPDATE TOP (10) Members
SET 
 member_id = member_id,
 process_status = 1
WHERE status = 0
OUTPUT inserted.member_ID
INTO @MyTableVar;

之后,@MyTableVar 应该包含所有更新的成员 ID。

【讨论】:

    【解决方案3】:

    为了实现让多个进程在成员表上工作的目标,您无需“玩弄锁”。您需要从 #tmp_member 表更改为全局临时表或永久表。该表还需要一个列来跟踪哪个进程正在管理成员行/

    您将需要一种方法来为将使用该表的每个进程提供某种 ID。然后将修改第一个查询以排除其他进程在表中的任何条目。第二个查询将被修改为仅包含此过程的那些条目

    【讨论】:

    • 在提示的帮助下没有实现与您建议的相同的第一个解决方案?
    猜你喜欢
    • 2016-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多