SQL Server 2008 - 选择析取行

时间:2011-06-03 10:41:57

标签: sql sql-server-2008 locking

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

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'/ P>

3 个答案:

答案 0 :(得分:3)

你需要提示。

请在此处查看我的回答: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. 以安全,并发的方式返回结果集
  4. ...然后使用此代码。

答案 1 :(得分:0)

问题是您的选择/更新不是原子的 - 第二个进程可能会在选择的第一个进程和更新之前选择前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。

答案 2 :(得分:0)

为了满足您在成员表上使用多个进程的目标,您不需要“玩锁定”。您需要将#tmp_member表更改为全局临时表或永久表。该表还需要一列来跟踪管理成员行/

的进程

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