Проблема с DeadLock многопоточного приложения в базе данных

Я работаю с многопоточным консольным приложением, в котором каждый поток в основном пытается получить строку TOP 1 «Файл» с соблюдением определенных критериев и блокирует ее (есть столбец LockID, который заполняется, когда это происходит, чтобы следующий поток выбирает следующую доступную `` разблокированную '' строку `` Файл '')

Ставим монитор на БД SQL Server и каждый раз тупик происходит на 2 запросах.

SELECT TOP 1 F.Id, F.ContentTypeId, F.ManufacturerId, F.DocumentTypeId, F.Name, F.Description, F.VersionId, F.LastChangedVersionOn, F.ReferenceCount, F.LastChangedReferencesOn, F.LastChangedImageOn, F.ImageSize, F.IsStale, F.InvalidFile, CT.Id, CT.Name, CT.MimeType, CT.IsMimeAttachment, CT.Extensions, CT.CanTrackVersions, CT.UseRemoteSource, CT.FullTextFilter, CT.ContentHandler, V.Id, V.Size, V.Hash, V.Title, DT.Id, DT.Code, DT.Ordinal, DT.Name, DT.PluralName, DT.UrlPart
FROM Docs.Files F
INNER JOIN Docs.ContentTypes CT ON CT.Id = F.ContentTypeId
LEFT JOIN Docs.Versions V ON V.Id = F.VersionId
LEFT JOIN Docs.DocumentTypes DT ON DT.Id = F.DocumentTypeId
WHERE (F.LockId IS NULL OR F.LockedOn < DATEADD(hh,-1,GETUTCDATE()))
AND F.IsStale = 1 AND F.InvalidFile = 0 

А ТАКЖЕ

(@Id int)UPDATE Docs.Files
SET LastChangedImageOn = GETUTCDATE(), ImageSize = (
    SELECT DATALENGTH(FileImage)
    FROM Docs.FileImages
    WHERE FileId = @Id)
WHERE Id = @Id;
SELECT TOP 1 LastChangedImageOn FROM Docs.Files WHERE Id = @Id    

Первый запрос выполняется, когда создается новый поток, и мы пытаемся получить новую строку «Файл».

Второй запрос выполняется, когда поток (может быть ранее созданным) почти завершил обработку записи «Файл». Используемые транзакции в этом запросе. Уровень изоляции был «ReadCommitted». Я почти уверен, что оба запроса не пытаются получить доступ к одному и тому же «FileID», потому что два потока впоследствии никогда не будут обрабатывать один и тот же «FileID». Я ужасно не понимаю, как я могу диагностировать эту проблему. Что могло вызвать взаимоблокировку между этими двумя запросами? Я был бы очень признателен, если бы кто-нибудь мог направить меня в правильном направлении. Заранее большое спасибо :)


person karry    schedule 29.08.2012    source источник
comment
Было бы полезно получить дополнительную информацию. - Какой сервер базы данных и движок (если применимо) вы используете? - Вы пользуетесь транзакциями? P.S. SQL означает язык структурированных запросов. Есть много БД, использующих SQL.   -  person Paul    schedule 29.08.2012
comment
Какие здесь уровни изоляции?   -  person Marc Gravell    schedule 29.08.2012
comment
Кроме того, единственное возражение, которое я вижу, касается Docs.Files - с чтением и записью, которые, вероятно, могут быть нарушены ... Опции: заставить чтение работать с меньшей (нулевой) изоляцией, чтобы не требовалось блокировки чтения; или сделайте чтение более изолированным, чтобы потребовалась блокировка записи (вызывая блокировку, а не тупик). Что звучит предпочтительнее?   -  person Marc Gravell    schedule 29.08.2012
comment
@MarcGravell Я использовал транзакции для второго рассматриваемого запроса. Я использовал уровень изоляции ReadCommited. Однако в запросе SELECT не было транзакции / изоляции.   -  person karry    schedule 29.08.2012
comment
@Paul Это база данных SQL-сервера. Дополнительную информацию см. В моем комментарии выше. Пожалуйста, дайте мне знать, если вам понадобится что-нибудь еще.   -  person karry    schedule 29.08.2012


Ответы (1)


Хм ... давно я ничего не делал с SQL Server. Но давай попробуем.

Вы упомянули, что «два потока никогда не будут обрабатывать один и тот же« FileID »впоследствии», как вы можете быть уверены в этом? Идентификатор загружается из источника вне потока?

person Paul    schedule 29.08.2012
comment
потому что строка будет заблокирована предыдущим потоком, а следующий поток заберет только разблокированные и неактивные строки. - person karry; 29.08.2012
comment
Похоже, там проблема. Настраивает ли поток те, что находятся в базе данных? Если да, то как насчет промежутка между запуском потока и завершением обновления? Мог ли другой поток запустить и получить тот же идентификатор файла? - person Paul; 30.08.2012
comment
Привет. Удалось ли вам найти решение вашей проблемы, и мои вопросы указали вам правильное направление? - person Paul; 04.02.2013
comment
Привет, @Paul Спасибо, что заглянули. Я думаю, что это была проблема с SQL-сервером, а не с кодом, которая вызвала тупик. Сервер был перегружен запросами, и ему не хватало памяти. Наши администраторы баз данных внесли некоторые корректировки ввода-вывода, и все заработало. Еще раз спасибо за проверку. - person karry; 05.02.2013
comment
Ой! Что ж, я рад, что проблема найдена и исправлена. :) - person Paul; 06.02.2013