Моя схема БД: Job -> (Many) JobData -> (Many) Results. Задание разбивается на несколько строк JobData, чтобы несколько потоков могли обрабатывать «фрагменты» задания (каждую строку JobData). Затем потоки обработки вставляют строки Result для каждой из строк JobData, которые он обрабатывает.
Один поток пытается прочитать результаты в цикле, пока не будут прочитаны все результаты. Обратите внимание, что в то же время потоки могут обрабатывать строки JobData (пока все не будут обработаны) и вставлять результаты. Таким образом, в цикле каждый вызов этого SP проходит в JobKey... но каким-то образом с этого кода результаты считываются несколько раз (очень низкая частота... т.е. ‹ 3 строки на 8000 строк результатов), но воспроизводятся только случайным образом.
Я добавил комментарий ниже в коде рядом с моим заявлением UPDATE TOP относительно UPDLOCK. Заранее спасибо.
BEGIN TRANSACTION
-- Create a temp table TO store the select results
DECLARE @UnReadResults TABLE
(
ResultKey uniqueidentifier
)
-- Wouldn't expect a UPDLOCK is needed since UPDATE statements create exclusive lock anyway? Do I need to SELECT WITH UPDLOCK first, then do the UPDATE statement?
UPDATE TOP ( @pageSize ) Result
SET rResultRead = 1
OUTPUT INSERTED.rKey INTO @UnReadResults
FROM Result r INNER JOIN JobData AS jd ON jd.jdKey = r.rJobDataKey
WHERE jd.jdJobKey = @jobKey AND rResultRead = 0
-- Just return Job (always the same), JobData (could vary if chunk of result rows
-- spans multiple JobDatas) and Results that I successfully 'grabbed' by joining
-- to my temp table
SELECT j.jKey, j.jStatus, j.jResultsRead,
jd.jdKey, jd.jdJobKey, jd.jdDateStart, jd.jdDateComplete, jd.jdStatus,
r.rKey, r.rProfileKey, r.rProfileAuthID, r.rResult, r.rReadLock, r.rReadAttempts
FROM Job j
INNER JOIN JobData jd
ON jKey = jdJobKey
INNER JOIN Result r
ON jdKey = rJobDataKey
INNER JOIN @UnReadResults urr
on rKey = urr.ResultKey
COMMIT TRANSACTION
РЕДАКТИРОВАТЬ: Просто хотел поставить то, что у меня есть сейчас, на основе ответа @gbn. Исключая весь SP, но оператор UPDATE теперь имеет следующий формат:
UPDATE TOP ( @pageSize ) Result
SET rResultRead = 1, rReadLock = @lock, rReadAttempts = rReadAttempts + 1
OUTPUT INSERTED.rKey INTO @UnReadResults
FROM Result r WITH ( ROWLOCK, READPAST, UPDLOCK ) INNER JOIN JobData AS jd ON jd.jdKey = r.rJobDataKey
WHERE jd.jdJobKey = @jobKey AND rResultRead = 0
Успешно работает уже несколько дней, так что, надеюсь, я решил проблему. Если это не похоже на правильное использование табличных подсказок, не стесняйтесь, дайте мне знать.
(ROWLOCK, READPAST, UPDLOCK)
- person gbn   schedule 19.01.2012