简体   繁体   中英

SQL Server 2008 - Select disjunct rows

I have two concurrent processes and I have two queries, eg.:

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

and then

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

I'd like each process to select different rows, so if a row was already selected by the first process, then do not use that one in the second process' result list.

Do I have to play around with locks? UPDLOCK, ROWLOCK, READPAST hints maybe? Or is there a more straightforward solution?

Any help is appreciated,

cheers,

b

You need hints.

See my answer here: SQL Server Process Queue Race Condition

However, you can shorten your query above into a single statement with the OUTPUT clause . Otherwise you'll need a transaction too (asuming each process executes the 2 statements above one after the other)

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

Summary: if you want multiple processes to

  1. select 10 rows where status = 0
  2. set process_status = 1
  3. return a resultset in a safe, concurrent fashion

...then use this code.

Well the problem is that your select/update is not atomic - the second process might select the first 10 items in between the first process having selected and before updating.

There's the OUTPUT clause you can use on the UPDATE statement to make it atomic. See the documentation for details, but basically you can write something like:

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;

After that @MyTableVar should contain all the updated member IDs.

To meet your goal of having multiple processes work on the member table you will not need to "play around with locks". You will need to change from the #tmp_member table to a global temp table or a permanate table. The table will also need a column to track which process is managing the member row/

You will need a method to provide some kind of ID to each process which will be using the table. The first query will then be modified to exclude any entries in the table by other processes. The second query will be modified to include only those entries by this process

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM