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

时间:2010-09-10 09:42:13

标签: sql-server sql-server-2005 tsql concurrency

我在存储过程中使用UPDLOCK和READPAST sql提示以实现一种表队列(我说排序因为我选择了前1500而不是前1,我不删除我选择它们之后的行。有关详细信息,请参阅问题Return unlocked rows in a "select top n" query)。

我用一个简单的小表做了一些测试,一切似乎都很好 - 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

测试表:

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 

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

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

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

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

非常欢迎任何想法!谢谢。

3 个答案:

答案 0 :(得分:4)

我认为你的问题是索引。确保您的表上有正确的索引,并确保您的查询始终使用该索引。没有或索引不正确会导致SQL Server占用页锁或表锁,这会使整个模型无效。

答案 1 :(得分:4)

以下是将表格用作队列的方法:SQL Server Process Queue Race Condition

总结:你错过了ROWLOCK(在这种情况下将使用更多资源)

答案 2 :(得分:0)

该表可能包含太多列,应该拆分。也许它不是正常的第3或第4范式。

另一件事是确保专门为您的查询设置覆盖索引。