Мне нужно настроить систему очередей, используя несколько таблиц SQL, например, описанную здесь .В связи с этим, и поскольку мне нужно фильтровать элементы в очереди по различным критериям, внутри хранимой процедуры я использую
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
, хотя мне нужно убедиться, что эти строки не обновляются в TableA
при любом другом параллельном запросе.Все идет хорошо до того момента, когда мне нужно вставить предложение ORDER BY
в любой из SELECT
выше, чтобы были выбраны только очень специфические идентификаторы (я действительно должен это сделать).Происходит следующее:
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), а второй ничего не вернет.Почему это?!