Por que as estimativas de linha do SQL Server mudam quando adiciono uma dica de associação?


15

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.


3
Você percebeu que possui uma junção externa, mas está usando a tabela na cláusula where?
James Z

@ JamesZ - sim, eu estou ciente disso, acho que não há um problema com isso.
Alexander Shelemin

9
@ AlexSh Bem, há um problema lógico / semântico com isso, porque isso altera sua associação externa para uma associação interna.
Aaron Bertrand

Respostas:


21

Ao ler diferentes artigos e livros, assumi que as estimativas de cardinalidade são realizadas antes da construção do plano.

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:

Fragmento de plano

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.

O que vejo, no entanto, é que a dica Mesclar faz com que todas as estimativas se tornem perfeitas.

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.

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.

É 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 ORDERmuita 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.


-10

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

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
  JOIN t4 
        ON t3.t4_id = t4.id 
       AND t4.id = some_GUID 

Ou melhor ainda - aposto que isso irá atender ou superar suas dicas ou força

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
       AND t3.t4_id = some_GUID

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.