Por que essa consulta causa um impasse?

11

Por que essa consulta causa um impasse?

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)

Gráfico de deadlock adicionado:

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

ADICIONADO:

Obrigado Sankar pelo artigo que possui soluções sobre como evitar esse tipo de impasse:

  • eliminar colunas desnecessárias da projeção do leitor para que ele não precise procurar o índice em cluster
  • adicione colunas necessárias como colunas contidas ao índice não em cluster para tornar a cobertura do índice novamente, para que o leitor não tenha que procurar o índice em cluster
  • Evite atualizações que precisam manter o índice não agrupado em cluster
garik
fonte
qual versão de qual plataforma db você está usando? qual é o nível padrão de isolamento de trx (ou simultaneidade)? Quais índices existem na tabela system_Queue atualmente?
SQLRockstar 04/04
@SQLRockstar parte do gráfico de deadlock adicionada, sql server 2008
garik
@SQLRockstar IX_system_Queue_DirectionByStatus index por IsOutGoing e StatusID.
Garik

Respostas:

13

Parece-me que você está tentando fazer um SELECT e um UPDATE na mesma instrução e na mesma tabela.

O SELECT está mantendo um bloqueio compartilhado nos valores dentro do índice IX_system_Queue_DirectionByStatus, e o UPDATE precisa que esses bloqueios sejam liberados antes que ele possa obter seu bloqueio exclusivo que atualizará a chave primária (que eu acho que está em cluster e também faz parte do (Valor da chave IX_system_Queue_DirectionByStatus).

De qualquer forma, meu palpite é que essa consulta só seria bem-sucedida com a rara chance de que os valores de índice selecionados e atualizados não sejam conflitantes. É um impasse cada vez que você executa (presumo que seria).

Aqui está um link que explica os impasses com mais detalhes: http://sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx

SQLRockstar
fonte
Bingo! Obrigado. Foi realmente uma situação estranha para o impasse que eu já vi. Obrigado pela resposta.
Garik