使用UPDLOCK选择top 1,READPAST在整个表上设置独占锁

Dia*_*ana 8 t-sql sql-server concurrency sql-server-2005

我在存储过程中使用UPDLOCK和READPAST sql提示以实现一种表队列(我说排序因为我选择前1500而不是前1,我不会删除后面的行选择它们.有关更多详细信息,请参阅"选择顶部n"查询中的返回未锁定行的问题.

我用一个简单的小表做了一些测试,一切似乎都很好 - SP的第二次调用不等待第一次调用结束,只是跳过第一次调用锁定的行,然后返回下一行.在我的真实桌子上,虽然,它有时只能工作......其他时候,第二个呼叫挂起并等待第一个呼叫结束.这是因为第一次调用会锁定整个表,而不仅仅是某些行.

这些是测试表和真实表的SP:

真表:

declare @temp as table (ID int primary key, timestamp datetime)

BEGIN TRANSACTION

insert into @temp
SELECT TOP 1 ID, getdate()
FROM subscription WITH (UPDLOCK, READPAST)
WHERE IsBeingProcessed = 0 

waitfor delay '00:00:10'

UPDATE subscription 
SET IsBeingProcessed = 1
from subscription
inner join @temp t on subscription.id = t.id

COMMIT TRANSACTION

select * from @temp t
inner join subscription s on s.id = t.id
Run Code Online (Sandbox Code Playgroud)

测试表:

declare @temp as table (ID int primary key)

BEGIN TRANSACTION

insert into @temp(id)
select top 1 id
from test WITH (UPDLOCK, READPAST)
where msg like 'test'

waitfor delay '00:00:10'

UPDATE test 
SET timestamp = getdate()
from test
inner join  @temp t1 on test.id = t1.id 

COMMIT TRANSACTION

select * from test t
inner join @temp t1 on t.id = t1.id 
Run Code Online (Sandbox Code Playgroud)

运行sp_lock我看到第一个SP在我的整个"真实"表上保存了一个独占表锁,而第二个SP则等待一个意图独占锁.对于我的"test"表,我对索引和行id进行了更新锁定,对两个页面进行了两次intent更新锁定,并对整个表进行了intent独占锁定.

有没有什么可能导致"真实表"的整个表锁?

也许我在那张桌子上有一些聚集索引,也许是我缺少的一些索引?我不知道.

我发布的示例非常简单 - 它有一个"前1"而没有"按顺序".我真正的选择将有一个"id by order"和"top 1500",可能是"top 3000".这可能会使锁定问题变得更糟.

任何ideea都非常欢迎!谢谢.

Ste*_*ven 5

我认为您的问题是索引编制。确保您的表上具有正确的索引,并确保查询始终使用该索引。没有索引或索引不正确会使SQL Server采取页锁或表锁,这会使整个模型失效。

  • @戴安娜:在那种情况下,我认为你有一个严重的问题。当使用`READPAST`和`UPDLOCK`时,您必须完全控制对该表执行的实际查询。当有人向该表添加索引或使用其他过滤器编写查询时,整个模型将崩溃。我可以凭经验说。我的建议是防止从应用程序直接访问表,并使用一些专门设计的存储过程来访问该表。 (5认同)