I need to set up a queue system using some SQL tables, like the one described here. That being, and since I need to filter queued items by different critera, inside a stored procedure I am using
BEGIN TRANSACTION
CREATE TABLE #Temp (ID INT, SOMEFIELD INT)
INSERT INTO #Temp SELECT TOP (@Something) TableA.ID, TableB.SomeField FROM TableA WITH (ROWLOCK, READPAST) INNER JOIN TableB WITH (UPDLOCK, READPAST) WHERE Condition1
INSERT INTO #Temp SELECT TOP (@Something) TableA.ID, TableB.SomeField FROM TableA WITH (ROWLOCK, READPAST) INNER JOIN TableB WITH (UPDLOCK, READPAST) WHERE Condition2
(...)
UPDATE TableB SET SomeField = 1 FROM TableB WITH (ROWLOCK, READPAST) WHERE ID IN (SELECT ID FROM #Temp)
COMMIT TRANSACTION
I am using ROWLOCK
in the first table and UPDLOCK
in the second because, after this select, I am going to update TableB
only, though I need to make sure that these lines don't get updated inTableA
by any other concurrent query. Everything goes well until the point where I need to insert an ORDER BY
clause in any of the SELECT
s above, so that only very specific IDs get selected (I must really do this). What happens is:
1) Without ORDER BY
, two concurrent executions execute as desired, returning different and non-overlapping results; however, they don't return the results I want because those precise results were outside the scope of every SELECT
statement.
2) Using ORDER BY
and two concurrent executions, only the first one returns results. The second one does not return anything.
I recall seeing on a blog that for these kind of queries with WITH (ROWLOCK, READPAST)
and ORDER BY
to work one needs to create indexes on the fields one is using in the ordering. I tried it, but I got the same results. How can I get past this problem?
Edit: For example, if I have a table TestTable
with fields (TestID INT, Value INT) and values "(1,1), (2,2), ..." and execute "simultaneously"
BEGIN TRANSACTION
SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST)
WAITFOR DELAY '00:00:05'
COMMIT TRANSACTION
the first execution returns lines (1,2) and the second one returns (3,4) as espected. However, if I execute
BEGIN TRANSACTION
SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST) ORDER BY VALUE ASC
WAITFOR DELAY '00:00:05'
COMMIT TRANSACTION
the first one returns (1, 2) and the second returns nothing. Why is this?!