【问题标题】:ORDER BY and WITH(ROWLOCK, UPDLOCK, READPAST)ORDER BY 和 WITH(ROWLOCK, UPDLOCK, READPAST)
【发布时间】:2011-09-17 08:23:18
【问题描述】:

我需要使用一些 SQL 表来设置队列系统,例如here 中描述的那个。也就是说,由于我需要按不同的标准过滤排队的项目,所以在我正在使用的存储过程中

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,但我需要确保这些行不会被更新inTableA 通过任何其他并发查询。一切都很顺利,直到我需要在上面的任何SELECTs 中插入一个ORDER BY 子句,以便只选择非常特定的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) 而第二个什么也不返回。这是为什么?!

【问题讨论】:

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


    【解决方案1】:

    如预期的那样

    • 带有 ORDER BY、不带 ROWLOCK、不带索引的 SELECT 将具有表锁,因为扫描/中间排序可以计算出 TOP 2。因此第二个会话由于 READPAST 而跳过整个表

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

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

    所以,你需要这两个

    • SELECT 查询(ROWLOCK、UPDLOCK、READPAST)中的 3 个提示用于控制粒度、隔离和并发性。
      仅使用 ROWLOCK 仍会导致对每一行进行排他锁进行扫描/排序。
    • Value 上的索引包括 TestID 以使 SELECT 高效。仅索引可能会修复并发性,但不能保证。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-25
      • 2016-04-20
      • 2013-11-21
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多