Почему этот запрос вызывает тупик?


11

Почему этот запрос вызывает тупик?

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>

ДОБАВЛЕНО:

Спасибо, Санкар, за статью, в которой есть решения, как избежать этого типа тупика:

  • исключить ненужные столбцы из проекции читателя, чтобы ему не приходилось искать кластерный индекс
  • добавьте обязательные столбцы в виде содержащихся столбцов в некластеризованный индекс, чтобы охватить индекс, опять же, чтобы читатель не мог искать кластеризованный индекс
  • избегайте обновлений, которые должны поддерживать некластеризованный индекс

какую версию какой базы данных вы используете? каков уровень изоляции (или параллелизма) trx по умолчанию? Какие индексы существуют в таблице system_Queue в настоящее время?
SQLRockstar

@SQLRockstar часть тупикового графа добавлен, SQL Server 2008
Гарик

@SQLRockstar IX_system_Queue_DirectionByStatus индекс по IsOutGoing и StatusID.
Гарик

Ответы:


13

Мне кажется, что вы пытаетесь выполнить 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


Бинго! Спасибо. Это была действительно странная ситуация для тупика, который я когда-либо видел. Спасибо за ответ.
Гарик

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.