Eu tenho uma consulta que une algumas tabelas e executa muito mal - as estimativas de linha estão muito distantes (1000 vezes) e a junção Nested Loops é escolhida, resultando em várias varreduras de tabela. A forma da consulta é bastante direta, parecida com esta:
SELECT t1.id
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
LEFT OUTER JOIN t4 ON t3.t4_id = t4.id
WHERE t4.id = some_GUID
Brincando com a consulta, notei que, quando sugiro que ela use uma junção de mesclagem para uma das junções, ela é executada muitas vezes mais rapidamente. Isso eu entendo - a junção de mesclagem é uma opção melhor para os dados que ingressam, mas o SQL Server simplesmente não calcula corretamente a escolha dos Loops Aninhados.
O que não entendo completamente é por que essa dica de associação altera todas as estimativas para todos os operadores do plano? Ao ler diferentes artigos e livros, presumi que as estimativas de cardinalidade são executadas antes da construção do plano; portanto, o uso de uma dica não alteraria as estimativas, mas instruiria explicitamente o SQL Server a usar uma implementação de junção física específica.
O que vejo, no entanto, é que a dica Mesclar faz com que todas as estimativas se tornem perfeitas. Por que isso acontece e existem técnicas comuns para fazer com que o otimizador de consultas faça uma estimativa melhor sem uma dica - considerando que as estatísticas obviamente permitem isso?
UPD: planos de execução anonimizados podem ser encontrados aqui: https://www.dropbox.com/s/hchfuru35qqj89s/merge_join.sqlplan?dl=0 https://www.dropbox.com/s/38sjtv0t7vjjfdp/no_hints_join.sqlplan?dl = 0
Eu verifiquei as estatísticas usadas pelas duas consultas usando TF 3604, 9292 e 9204, e essas são idênticas. No entanto, os índices examinados / pesquisados diferem entre as consultas.
Além disso, tentei executar a consulta OPTION (FORCE ORDER)
- ela é executada ainda mais rápido do que a junção de mesclagem, escolhendo HASH MATCH para cada junção.
fonte
Respostas:
Não exatamente. Uma estimativa de cardinalidade inicial é derivada (após simplificações e outros trabalhos), que influencia a ordem de junção inicial escolhida pelo otimizador.
No entanto, explorações subsequentes (durante a otimização baseada em custos) podem, e geralmente resultam, em novas estimativas de cardinalidade sendo calculadas. Esses CEs posteriores podem ser mais ou menos "precisos". Se houver uma subestimação, o otimizador poderá escolher um plano que pareça mais barato, mas que na verdade é executado por muito mais tempo.
Em geral, não há garantia de que as estimativas de cardinalidade para subárvores semanticamente idênticas produzam os mesmos resultados. É um processo estatístico, afinal, e algumas operações têm um apoio mais profundo da CE do que outras.
No seu caso, parece haver outro fator - o otimizador apresenta (ou se move) um Top, que define uma meta de linha na subárvore abaixo:
Se você ativar o sinalizador de rastreamento 4138 (em 2008 R2 ou posterior), poderá encontrar as estimativas mais alinhadas com as expectativas ou talvez até o otimizador não escolha mais loops aninhados.
Há um elemento de sorte envolvido aqui. As pessoas tendem a escrever consultas, ou pelo menos as junções, na ordem em que esperam que sejam realizadas fisicamente. O uso de uma dica de junção vem com um implícito
FORCE ORDER
, fixando assim a ordem de junção para corresponder à forma textual e desativando muitas regras de exploração do otimizador que podem levar a uma nova estimativa de cardinalidade.É o mesmo que sugerir uma junção, mas não restringe a escolha do operador de junção física. Novamente, se você escreveu a ordem de junção da consulta de uma maneira lógica, é bem provável que você obtenha um plano razoável. Obviamente, você perde muitas das habilidades do otimizador dessa maneira, o que pode não produzir resultados ideais em situações mais gerais.
Você provavelmente não desejará usá-lo com
FORCE ORDER
muita frequência, pois é uma dica (diretiva) extremamente poderosa que tem efeitos mais amplos do que simples forçar a ordem das junções; por exemplo, evita que o otimizador mova agregações e introduza agregações parciais. Aconselho muito a não usar essa dica, exceto em circunstâncias muito excepcionais e por afinadores verdadeiramente experientes .Uma análise detalhada exigiria mais tempo do que eu tenho agora e acesso a uma cópia apenas do estatística do banco de dados.
fonte
O onde nega a esquerda
Por que dificultar o otimizador?
Com 3 ou mais junções, o otimizador tenderá a ficar na defensiva e entrar em loop porque protege a memória
Uma condição ou na junção também tenderá a entrar em uma junção de loop - tenho provas concretas de que isso sempre acontece - não - ainda uma realidade
Com várias junções, puxe as condições de onde para a junção quando você puder
Ou melhor ainda - aposto que isso irá atender ou superar suas dicas ou força
O problema com as dicas é que elas são para dados em um estado específico. Escreva uma consulta limpa e deixe o otimizador fazer seu trabalho. Algumas vezes, ele só precisa de mais estatísticas para fazer a coisa certa, mas depois trava.
Por que diferentes estimativas. A planos diferentes. Comece com consultas que dão ao otimizador uma chance de lutar.
fonte