Выбрать верхнюю 1 с помощью UPDLOCK и READPAST устанавливает эксклюзивную блокировку для всей таблицы

Я использую подсказки SQL UPDLOCK и READPAST в хранимая процедура для реализации своего рода табличной очереди (я говорю «сортировка», потому что я выбираю первые 1500 вместо первой 1, и я не удаляю строки после того, как выберу их. Подробнее см. вопрос ] Возвращать разблокированные строки в запросе "select top 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

Тестовая таблица:

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 I увидим, что эксклюзивная блокировка таблицы удерживается первым SP на всей моей «реальной» таблице, в то время как второй SP ожидает с намеренной монопольной блокировкой. Для моей «тестовой» таблицы у меня есть блокировка обновления индекса и идентификатора строки, две блокировки намеренного обновления на двух страницах и эксклюзивная блокировка намерения для всей таблицы.

Есть ли у вас какая-нибудь идея, что могло бы вызвать блокировку всей таблицы "реальной таблицы"?

Может быть, какие-то кластерные индексы, которые у меня есть в этой таблице, может быть, какие-то индексы мне не хватает? Я не знаю.

Пример, который я опубликовал, очень прост - в нем есть «первые 1» и нет «порядка по». Мой настоящий выбор будет иметь «порядок по идентификатору» и «топ 1500», возможно, «топ 3000». Это может усугубить проблему блокировки.

Любые идеи приветствуются! Спасибо.

8
задан Community 23 May 2017 в 12:26
поделиться