SELECTs não podem travar com outros SELECTs, porque eles apenas adquirem travas compartilhadas. Você diz que devemos considerar que esses SELECTs agora 'requer bloqueios de leitura exclusivos', mas isso não é possível considerarmos porque 1) não existe um
exlusive read lock
e 2) as leituras não adquirem bloqueios exclusivos. Mas você coloca uma questão mais geral, se declarações simples podem travar. A resposta é um definitivo e retumbante SIM . Os bloqueios são adquiridos na execução, não analisados antecipadamente e classificados e adquiridos em alguma ordem. Seria impossível para o mecanismo saber antecipadamente os bloqueios necessários porque eles dependem dos dados reais no disco e ler os dados que o mecanismo precisa para ... bloquear os dados.
Deadlocks entre instruções simples (SELECt vs. UPDATE ou SELECT vs. DELETE) devido a diferentes ordens de acesso ao índice são bastante comuns e muito fáceis de investigar, diagnosticar e corrigir. Mas observe que há sempre uma operação de gravação envolvida, pois as leituras não podem bloquear umas às outras. Para esta discussão, adicionar uma dica UPDLOCK ou XLOCK a um SELECT deve ser considerado uma gravação. Você nem precisa de um JOIN, um índice secundário pode introduzir o problema da ordem de acesso que leva ao impasse, consulte Ler/Gravar Deadlock .
E finalmente, escrevendo
SELECT FROM A JOIN B
ou escrevendo SELECT FROM B JOIN A
é completamente irrelevante. O otimizador de consulta é livre para reorganizar a ordem de acesso como achar melhor, o texto real da consulta não impõe a ordem de execução de forma alguma. Atualizado
Receio que não haja nenhuma receita de cortador de biscoitos. A solução vai depender de caso para caso. Em última análise, em aplicativos de banco de dados, os deadlocks são um fato da vida. Eu entendo que isso pode parecer absurdo, como em 'nós pousamos na Lua, mas não podemos escrever um aplicativo de banco de dados correto', mas há fortes fatores em jogo que praticamente garantem que os aplicativos eventualmente encontrarão impasses. Os impasses de sorte são os mais fácil de lidar com erros, simples ler novamente o estado, aplicar a lógica, reescrever o novo estado. Dito isso, existem algumas boas práticas que podem reduzir drasticamente a frequência de deadlocks, até o ponto em que eles desaparecem:
- Tente ter um padrão de acesso consistente para Gravações . Tenha regras claramente definidas informando coisas como 'uma transação deve sempre apresentar tabelas nesta ordem:
Customers
->OrderHeaders
->OrderLines
.' Observe que a ordem deve ser obedecida dentro de uma transação . Basicamente, classifique todos tabelas em seu esquema e especifique que todas as atualizações devem ocorrer em ordem de classificação. Isso eventualmente se resume à disciplina de código do colaborador individual que escreve o código, pois ele precisa garantir que ele escreva a atualização na ordem correta dentro de uma transação. - Reduza a duração de escreve. A sabedoria usual é a seguinte:no início da transação, faça todas as leituras (leia o estado existente), processe a lógica e calcule novos valores e, em seguida, escreva todas as atualizações no final da transação. Evite um padrão como 'ler->escrever->lógico->ler->escrever', em vez disso, faça 'ler->ler->lógico->gravar->gravar'. É claro que o verdadeiro artesanato consiste em como lidar com casos reais, reais e individuais, quando aparentemente se deve tem que fazer gravações no meio da transação. Uma nota especial aqui deve ser dita sobre um tipo específico de transação:aquelas dirigidas por uma fila, que por definição iniciam sua atividade por desenfileiramento (=uma escrita) da fila. Esses aplicativos sempre foram notoriamente difíceis de escrever e propensos a erros (especialmente deadlocks), felizmente existem maneiras de fazer isso, veja Usando tabelas como filas .
- Reduza a quantidade de leituras. As varreduras de tabela são as causa mais comum de bloqueios. A indexação adequada não apenas eliminará os impasses, mas também aumentará o desempenho no processo.
- Isolamento de instantâneo . Esta é a coisa mais próxima que você terá de um almoço grátis em relação a evitar impasses. Eu intencionalmente coloquei por último, porque pode mascarar outros problemas (como indexação imprópria) em vez de corrigi-los.
Tentando resolver este problema com um
LockCustomerByXXX
abordagem, temo que não funcione. Bloqueio pessimista não escala. Simultaneidade otimista
as atualizações são as caminho a percorrer se você quiser ter qualquer tipo de desempenho decente.