Dlaczego to zapytanie powoduje zakleszczenie?

11

Dlaczego to zapytanie powoduje zakleszczenie?

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)

Dodano wykres zakleszczenia:

<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>

DODANY:

Dziękujemy Sankarowi za artykuł, który zawiera rozwiązania, jak uniknąć tego typu impasu:

  • wyeliminuj niepotrzebne kolumny z projekcji czytelnika, aby nie musiał szukać indeksu klastrowego
  • dodaj wymagane kolumny jako zawarte kolumny do indeksu nieklastrowanego, aby indeks obejmował się ponownie, aby czytelnik nie sprawdził indeksu klastrowanego
  • unikaj aktualizacji, które muszą utrzymywać indeks nieklastrowany
garik
źródło
jakiej wersji platformy db używasz? jaki jest domyślny poziom izolacji (lub współbieżności) trx? Jakie indeksy istnieją obecnie w tabeli system_Queue?
SQLRockstar
@SQLRockstar dodana część wykresu zakleszczenia, serwer SQL 2008
gar
@SQLRockstar IX_system_Queue_DirectionByStatus indeks według IsOutGoing i StatusID.
garik

Odpowiedzi:

13

Wydaje mi się, że próbujesz wykonać SELECT i UPDATE w tej samej instrukcji i na tej samej tabeli.

SELECT utrzymuje wspólną blokadę wartości w indeksie IX_system_Queue_DirectionByStatus, a UPDATE potrzebuje zwolnienia tych blokad, zanim będzie w stanie uzyskać blokadę wyłączną, która zaktualizuje klucz podstawowy (który, jak sądzę, jest klastrowany, a także część IX_system_Queue_DirectionByStatus wartość klucza).

W każdym razie, przypuszczam, że to zapytanie powiedzie się tylko przy rzadkiej szansie, że wybrane i zaktualizowane wartości indeksu nie powodują konfliktu. Czy blokuje się przy każdym wykonaniu (zakładam, że tak będzie).

Oto link, który bardziej szczegółowo wyjaśnia zakleszczenia: http://sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx

SQLRockstar
źródło
Bingo! Dziękuję Ci. To była naprawdę dziwna sytuacja dla impasu, jaki kiedykolwiek widziałem. Dziękuję za odpowiedź.
garik