No trecho de plano de consulta a seguir, parece óbvio que a estimativa de linha para o Concatenation
operador deve ser ~4.3 billion rows
, ou a soma das estimativas de linha para suas duas entradas.
No entanto, uma estimativa de ~238 million rows
é produzida, levando a uma estratégia Sort
/ abaixo do ideal Stream Aggregate
que derrama centenas de GB de dados em tempdb. Uma estimativa logicamente consistente neste caso teria produzido um Hash Aggregate
, removido o derramamento e melhorado drasticamente o desempenho da consulta.
Isso é um bug no SQL Server 2014? Existem circunstâncias válidas nas quais uma estimativa menor do que as entradas poderia ser razoável? Que soluções alternativas podem estar disponíveis?
Aqui está o plano de consulta completo (anônimo). Não tenho acesso de administrador de sistema a este servidor para fornecer saídas QUERYTRACEON 2363
ou sinalizadores de rastreamento semelhantes, mas posso obter essas saídas de um administrador se forem úteis.
O banco de dados está no nível de compatibilidade 120 e, portanto, está usando o novo Estimador de cardinalidade do SQL Server 2014.
As estatísticas são atualizadas manualmente toda vez que os dados são carregados. Dado o volume de dados, estamos usando a taxa de amostragem padrão. É possível que uma taxa de amostragem mais alta (ou FULLSCAN
) possa ter um impacto.
Para citar Campbell Fraser neste item do Connect :
Para expandir um pouco: A maneira que gosto de explicar é dizer que a estimativa de cardinalidade inicial (realizada antes do início da otimização baseada em custo) produz estimativas de cardinalidade mais "consistentes", pois toda a árvore inicial é processada, com cada subseqüente estimativa dependente diretamente da anterior.
Durante a otimização baseada em custo, partes da árvore do plano (um ou mais operadores) podem ser exploradas e substituídas por alternativas, cada uma das quais pode exigir uma nova estimativa de cardinalidade. Não há uma maneira geral de dizer qual estimativa será geralmente melhor do que outra, então é bem possível acabar com um plano final que parece "inconsistente". Isso é simplesmente o resultado de costurar "pedaços de planos" para formar o arranjo final.
Dito isso, houve algumas alterações detalhadas no novo estimador de cardinalidade (CE) introduzido no SQL Server 2014 que torna isso um pouco menos comum do que no caso do CE original.
Além de atualizar para a atualização cumulativa mais recente e verificar se as correções do otimizador com 4199 estão ativadas, suas principais opções são tentar alterações de estatísticas/índice (observando os avisos de índices ausentes) e atualizações ou expressar a consulta de maneira diferente. O objetivo é adquirir um plano que exiba o comportamento que você precisa. Isso pode ser congelado com um guia de plano, por exemplo.
O plano anônimo dificulta a avaliação dos detalhes, mas também examinaria cuidadosamente os bitmaps para ver se eles são do tipo 'otimizado' (Opt_Bitmap) ou pós-otimização (Bitmap). Também desconfio dos Filtros.
Se as contagens de linhas forem precisas, isso parece uma consulta que pode se beneficiar de columnstore. Além dos benefícios usuais, você pode aproveitar a concessão de memória dinâmica para operadores de modo de lote ( o sinalizador de rastreamento 9389 pode ser necessário).
Construir um banco de teste reconhecidamente bastante simples no SQL Server 2012 (11.0.6020) me permite recriar um plano com duas consultas combinadas de hash sendo concatenadas por meio de um arquivo
UNION ALL
. Meu test-bed não exibe a estimativa incorreta que você vê. Talvez este seja um problema do SQL Server 2014 CE.Obtenho uma estimativa de 133.785 linhas para uma consulta que na verdade retorna 280 linhas, no entanto, isso é esperado, como veremos mais adiante:
Acho que o motivo é a falta de estatísticas para as duas junções resultantes que são UNIONed. O SQL Server precisa fazer suposições fundamentadas na maioria dos casos em torno da seletividade das colunas quando confrontado com a falta de estatísticas.
Joe Sack tem uma leitura interessante sobre isso aqui .
Para um
UNION ALL
, é seguro dizer que veremos exatamente o número total de linhas retornadas por cada componente da união, no entanto, como o SQL Server está usando estimativas de linha para os dois componentes doUNION ALL
, vemos que ele adiciona o total de linhas estimadas de ambos consultas para obter a estimativa para o operador de concatenação.No meu exemplo acima, o número estimado de linhas para cada parte do
UNION ALL
é 66,8927, que quando somado é igual a 133,785, que vemos para o número estimado de linhas para o operador de concatenação.O plano de execução real para a consulta união acima se parece com:
Você pode ver o número "estimado" vs "real" de linhas. No meu caso, adicionar o número "estimado" de linhas retornadas pelos dois operadores de correspondência de hash é exatamente igual ao valor mostrado pelo operador de concatenação.
Eu tentaria obter a saída do rastreamento 2363 etc, conforme recomendado na postagem de Paul White que você mostra em sua pergunta. Como alternativa, você pode tentar usar
OPTION (QUERYTRACEON 9481)
na consulta para reverter para a versão 70 CE para ver se isso "corrige" o problema.