私のDBスキーマはJob->(Many)JobData->(Many)Resultsです。ジョブは複数のJobData行に分割されるため、複数のスレッドがジョブの「チャンク」(各JobData行)を処理できます。次に、処理スレッドは、処理するJobData行ごとに結果行を挿入します。
単一のスレッドは、すべての結果が読み取られるまで、ループで結果を読み取ろうとします。 同時に、スレッドはJobData行を処理し(すべてが処理されるまで)、結果を挿入できることに注意してください。 したがって、ループでは、このSPへの各呼び出しはJobKeyを渡します...しかし、どういうわけかこのコードを使用すると、結果は複数回読み取られます(非常に低い頻度...つまり、結果の8000行あたり3行未満)が、ランダムにしか再現できません。
UPDLOCKに関するUPDATETOPステートメントの横のコードに以下のコメントを追加しました。前もって感謝します。
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
数日間正常に実行されているので、うまくいけば問題を解決しました。これがテーブルヒントの適切な使用に見えない場合は、遠慮なくお知らせください。