Eu tenho 2 consultas que quando executadas ao mesmo tempo estão causando um impasse.
Consulta 1 - atualize uma coluna que está incluída em um índice (index1):
update table1 set column1 = value1 where id = @Id
Pega o X-Lock na table1 e tenta um X-Lock no index1.
Consulta 2:
select columnx, columny, etc from table1 where {some condition}
Pega um S-Lock no index1 e tenta um S-Lock na table1.
Existe uma maneira de evitar o impasse mantendo as mesmas consultas? Por exemplo, posso de alguma forma fazer um X-Lock no índice na transação de atualização antes da atualização para garantir que a tabela e o acesso ao índice estejam na mesma ordem - o que deve evitar o impasse?
O nível de isolamento é Read Committed. Os bloqueios de linha e página estão ativados para os índices. É possível que o mesmo registro esteja participando das duas consultas - não sei dizer pelo gráfico de deadlock, pois não mostra os parâmetros.
O gráfico de impasse mostra que esse impasse específico era um impasse de conversão associado a uma pesquisa de marcador (uma pesquisa RID neste caso):
Como observa a pergunta, o risco de impasse geral surge porque as consultas podem obter bloqueios incompatíveis nos mesmos recursos em ordens diferentes. A
SELECT
consulta precisa acessar o índice antes da tabela devido à pesquisa RID, enquanto aUPDATE
consulta modifica primeiro a tabela e depois o índice.A eliminação do impasse requer a remoção de um dos ingredientes do impasse. Seguem as principais opções:
SELECT
consulta retorna 26 colunas.Proposal
. Vale a pena considerar isso, embora pareça que esta coluna é do tipouniqueidentifier
, o que pode ou não ser uma boa escolha para um índice clusterizado, dependendo de questões mais amplas.READ_COMMITTED_SNAPSHOT
ou doSNAPSHOT
banco de dados. Isso exigiria testes cuidadosos, especialmente com relação a qualquer comportamento de bloqueio projetado. O código do gatilho também exigiria testes para garantir que a lógica funcionasse corretamente.READ UNCOMMITTED
nível de isolamento para aSELECT
consulta. Todas as ressalvas usuais se aplicam.Você pode tentar isso agrupando a atualização em uma transação explícita e executando um
SELECT
com umaXLOCK
dica no valor do índice não clusterizado antes da atualização. Isso depende de você saber com certeza qual é o valor atual no índice não clusterizado, obter o plano de execução correto e antecipar corretamente todos os efeitos colaterais de obter esse bloqueio extra. Ele também depende do mecanismo de travamento não ser inteligente o suficiente para evitar a trava se for considerado redundante .Em suma, embora isso seja viável em princípio, não o recomendo. É muito fácil perder alguma coisa, ou ser mais esperto de maneiras criativas. Se você realmente deve evitar esses impasses (em vez de apenas detectá-los e tentar novamente), eu o encorajaria a examinar as soluções mais gerais listadas acima.
Eu tenho um problema semelhante que ocorre ocasionalmente e aqui está a abordagem que eu tomo.
set deadlock priority low;
ao select. Isso fará com que essa consulta seja a vítima do impasse quando ocorrer um impasse.Observação: se você fizer
select
parte de uma transação explícita de várias instruções, certifique-se de tentar novamente toda a transação, e não apenas a instrução que falhou, caso contrário, poderá obter alguns resultados inesperados. Se for um únicoselect
, tudo bem, mas se for uma declaração dentrox
den
uma transação, certifique-se de repetir todas asn
declarações durante a nova tentativa.