Почему этот запрос вызывает тупик?
UPDATE TOP(1) system_Queue SET
[StatusID] = 2,
@ID = InternalID
WHERE InternalID IN (
SELECT TOP 1
InternalID FROM system_Queue
WHERE IsOutGoing = @IsOutGoing AND StatusID = 1
ORDER BY MessageID ASC, InternalID ASC)
Добавлен график тупиковой ситуации:
<keylock hobtid="72057594236436480" dbid="9" objectname="Z.dbo.system_Queue" indexname="PK_system_Queue" id="lock5b25cc80" mode="X" associatedObjectId="72057594236436480">
<owner-list>
<owner id="processc6fe40" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="processc7b8e8" mode="S" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594405453824" dbid="9" objectname="Z.dbo.system_Queue" indexname="IX_system_Queue_DirectionByStatus" id="lock48cf3180" mode="S" associatedObjectId="72057594405453824">
<owner-list>
<owner id="processc7b8e8" mode="S"/>
</owner-list>
<waiter-list>
<waiter id="processc6fe40" mode="X" requestType="wait"/>
</waiter-list>
</keylock>
ДОБАВЛЕНО:
Спасибо, Санкар, за статью, в которой есть решения, как избежать этого типа тупика:
- исключить ненужные столбцы из проекции читателя, чтобы ему не приходилось искать кластерный индекс
- добавьте обязательные столбцы в виде содержащихся столбцов в некластеризованный индекс, чтобы охватить индекс, опять же, чтобы читатель не мог искать кластеризованный индекс
- избегайте обновлений, которые должны поддерживать некластеризованный индекс
sql-server-2008
deadlock
Гарик
источник
источник
Ответы:
Мне кажется, что вы пытаетесь выполнить SELECT и UPDATE в одном выражении и в одной и той же таблице.
SELECT удерживает общую блокировку для значений внутри индекса IX_system_Queue_DirectionByStatus, и UPDATE необходимо, чтобы эти блокировки были сняты, прежде чем он сможет получить свою эксклюзивную блокировку, которая обновит первичный ключ (который, как я предполагаю, является кластеризованным, а также частью Значение ключа IX_system_Queue_DirectionByStatus).
В любом случае, я предполагаю, что этот запрос будет успешным только при редкой вероятности того, что значения индекса, которые он выбирает и обновляет, не конфликтуют. Это блокировка каждый раз, когда вы выполняете (я предполагаю, что это будет).
Вот ссылка, которая более подробно объясняет взаимоблокировки: http://sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx
источник
Я не ожидаю, что вы отметите этот пост как ответ, но поделитесь здесь дополнительной информацией с другими экспертами по SQL Server по этой теме.
http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
http://rusanu.com/2009/05/16/readwrite-deadlock/
источник