ORDER BY和WITH(ROWLOCK,UPDLOCK,READPAST)

时间:2011-06-17 16:36:57

标签: sql-server-2005 locking sql-order-by

我需要使用一些SQL表来设置队列系统,如here所描述的那样。那就是,因为我需要通过不同的critera过滤排队的项目,在我使用的存储过程中

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

我在第一个表中使用ROWLOCK,在第二个表中使用UPDLOCK,因为在此选择之后,我将仅更新TableB,但我需要确保这些任何其他并发查询都不会在TableA中更新这些行。一切顺利,直到我需要在上面的任何ORDER BY中插入SELECT子句,以便只选择非常具体的ID(我必须这样做)。会发生什么:

1)没有ORDER BY,两个并发执行按需执行,返回不同且不重叠的结果;但是,它们不会返回我想要的结果,因为这些精确的结果超出了每个SELECT语句的范围。

2)使用ORDER BY和两个并发执行,只有第一个返回结果。第二个不会返回任何内容。

我记得在博客上看到,对于WITH (ROWLOCK, READPAST)ORDER BY的这类查询,需要在排序中使用的字段上创建索引。我尝试过,但结果相同。我怎样才能解决这个问题?

编辑:例如,如果我有一个表TestTable,其中包含字段(TestID INT,Value INT)和值“(1,1),(2,2),. ..“并同时执行”

BEGIN TRANSACTION

SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST)

WAITFOR DELAY '00:00:05'

COMMIT TRANSACTION

第一次执行返回第(1,2)行,第二次执行返回(3,4)。但是,如果我执行

BEGIN TRANSACTION

SELECT TOP 2 TestID FROM TestTable WITH (UPDLOCK, READPAST) ORDER BY VALUE ASC

WAITFOR DELAY '00:00:05'

COMMIT TRANSACTION

第一个返回(1,2),第二个返回任何内容。这是为什么?!

1 个答案:

答案 0 :(得分:6)

正如预期的那样

  • 带有ORDER BY的SELECT,没有ROWLOCK,没有索引会有一个表锁,因为扫描/中间排序可以解决TOP 2.所以第二个会话因为READPAST而跳过整个表

  • 没有ORDER BY的SELECT只是挑选任意2行,这恰好是插入的顺序(纯巧合,没有隐含的顺序)。这两行被锁定的事实导致第二个会话跳到下一个非锁定行。

SQL Server尝试尽可能保持锁定,但扫描意味着表锁定。现在,这通常不会产生影响(它是一个共享的读锁定)但你也有UPDLOCK,这意味着一个独占锁定的表

所以,你需要这两个

  • SELECT查询中的3个提示(ROWLOCK,UPDLOCK,READPAST)以控制粒度,隔离和并发。
    仅使用ROWLOCK仍会导致每行扫描/排序的独占锁定。
  • Value INCLUDE TestID上的索引,以提高SELECT效率。索引只能修复并发性,但不能保证。

在您之前的一个问题中,我将答案(在评论中)与SQL Server Process Queue Race Condition相关联,其中我有3个锁定提示