Trx issues: SELECT FOR UPDATE LIMIT - Mailing list pgsql-hackers

From James Mancz
Subject Trx issues: SELECT FOR UPDATE LIMIT
Date
Msg-id 20030430144949.8F187475458@postgresql.org
Whole thread Raw
Responses Re: Trx issues: SELECT FOR UPDATE LIMIT  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Is the behaviour I describe below expected?  I'm thinking that it isn't,
especially when compared with the comparable behaviour from Oracle and Sybase.

I'm running PostgreSQL 7.3.2.

I believe the problem is with transaction behaviour when using SELECT ... FOR
UPDATE with LIMIT.

I'll describe this by way of SQL to reproduce the issue:

Preparation:

CREATE TABLE work
(id int,alloc int null);

INSERT INTO work VALUES (1, NULL);
INSERT INTO work VALUES (2, NULL);

Basically, the idea is that the work table in reality includes millions of rows
of 'work' for various clients to share.  The client will grab a batch of rows,
process them, and then write the rows back to the database.

To grab a batch of rows to process, the client will SELECT a number of them, and
then update the alloc field to the ID of that client, thus marking them as being
worked on/work completed so that other clients don't process the same rows.

So, each client would do

BEGIN;
SELECT * FROM work WHERE alloc IS NULL LIMIT 1 FOR UPDATE; (of course, in reality, the LIMIT value here would be 1000
orwhatever and the  
work table would include lots of additional data for the client to process)
UPDATE work SET alloc = 99 WHERE id = 1;
COMMIT;

The problem occurs when one or more SELECTs occur while another SELECT is in
progress; use this to reproduce:

So, client 1 sends:

BEGIN;
SELECT * FROM work WHERE alloc IS NULL LIMIT 1 FOR UPDATE;

at this time the table values are:

id    alloc
----- --------   1     NULL   2     NULL

meanwhile client 2 sends:

BEGIN;
SELECT * FROM work WHERE alloc IS NULL LIMIT 1 FOR UPDATE;

This, of course, waits for client 1 to finish.

client 1 sends:

UPDATE work SET alloc = 99 WHERE id = 1;
COMMIT;

at this time the table values are:

id    alloc
----- --------   1       99   2     NULL

client 2 can carry on processing now,
and its SELECT * FROM work WHERE alloc IS NULL LIMIT 1 FOR UPDATE; **returns no
rows** despite the fact the second row matches.

It _should_ return:

id    alloc
----- --------   2     NULL

When similar functionality it tried on Oracle and Sybase (using their "versions"
of LIMIT -- rownum and SET rowcount respectively), they both return the second
row.

Thoughts?

james@mancz.com


--- Msg sent via WebMail@mancz.com - http://mail.mancz.com



pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Cygwin PostgreSQL CVS build issues
Next
From: Tom Lane
Date:
Subject: Re: Trx issues: SELECT FOR UPDATE LIMIT