Existe uma maneira de evitar o impasse, mantendo as mesmas consultas?
O gráfico de deadlock mostra que esse deadlock específico era um deadlock de conversão associado a uma pesquisa de marcador (neste caso, uma pesquisa RID):
Como observa a pergunta, o risco geral de conflito 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 do RID, enquanto a UPDATE
consulta modifica a tabela primeiro e depois o índice.
Eliminar o impasse requer a remoção de um dos ingredientes do impasse. A seguir, são apresentadas as principais opções:
- Evite a pesquisa do RID, fazendo a cobertura do índice não clusterizado. Provavelmente, isso não é prático no seu caso, porque a
SELECT
consulta retorna 26 colunas.
- Evite a pesquisa do RID, criando um índice em cluster. Isso envolveria a criação de um índice em cluster na coluna
Proposal
. Vale a pena considerar, embora pareça que essa coluna seja do tipo uniqueidentifier
, que pode ou não ser uma boa opção para um índice em cluster, dependendo de problemas mais amplos.
- Evite usar bloqueios compartilhados ao ler, ativando as opções
READ_COMMITTED_SNAPSHOT
ou do SNAPSHOT
banco de dados. Isso exigiria testes cuidadosos, especialmente com relação a comportamentos de bloqueio projetados. O código de acionamento também exigiria testes para garantir que a lógica funcione corretamente.
- Evite usar bloqueios compartilhados ao ler usando o
READ UNCOMMITTED
nível de isolamento da SELECT
consulta. Todas as advertências usuais se aplicam.
- Evite a execução simultânea das duas consultas em questão usando um bloqueio de aplicativo exclusivo (consulte sp_getapplock ).
- Use as dicas de bloqueio de tabela para evitar simultaneidade. Este é um martelo maior que a opção 5, pois pode afetar outras consultas, não apenas as duas identificadas na pergunta.
De alguma forma, posso usar 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
Você pode tentar isso, envolvendo a atualização em uma transação explícita e executando uma SELECT
com uma XLOCK
dica sobre o 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, acertar o plano de execução e antecipar corretamente todos os efeitos colaterais de usar esse bloqueio extra. Ele também conta com o mecanismo de bloqueio que não é inteligente o suficiente para evitar o bloqueio, se for considerado redundante .
Em resumo, embora isso seja viável em princípio, eu não o recomendo. É muito fácil perder algo ou ser mais esperto do que isso de maneiras criativas. Se você realmente deve evitar esses impasses (em vez de apenas detectá-los e tentar novamente), recomendamos que você procure as soluções mais gerais listadas acima.