我在存储过程中使用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”。这可能会使锁定问题变得更糟。
非常欢迎任何想法!谢谢。
答案 0 :(得分:4)
我认为你的问题是索引。确保您的表上有正确的索引,并确保您的查询始终使用该索引。没有或索引不正确会导致SQL Server占用页锁或表锁,这会使整个模型无效。
答案 1 :(得分:4)
以下是将表格用作队列的方法:SQL Server Process Queue Race Condition
总结:你错过了ROWLOCK(在这种情况下将使用更多资源)
答案 2 :(得分:0)
该表可能包含太多列,应该拆分。也许它不是正常的第3或第4范式。
另一件事是确保专门为您的查询设置覆盖索引。