Para uma consulta moderadamente complexa que estou tentando otimizar, observei que a remoção da TOP n
cláusula altera o plano de execução. Eu teria imaginado que, quando uma consulta inclui TOP n
o mecanismo de banco de dados, ela executa a consulta ignorando a TOP
cláusula the e, no final, diminui o resultado definido para o número n de linhas solicitadas. O plano gráfico de execução parece indicar que este é o caso - TOP
é o "último" passo. Mas parece que há mais coisas acontecendo.
Minha pergunta é: como (e por que) uma cláusula TOP n afeta o plano de execução de uma consulta?
Aqui está uma versão simplificada do que está acontecendo no meu caso:
A consulta está combinando linhas de duas tabelas, A e B.
Sem a TOP
cláusula, o otimizador estima que haverá 19k linhas da tabela A e 46k linhas da tabela B. O número real de linhas retornadas é 16k para A e 13k para B. Uma correspondência de hash é usada para unir esses dois conjuntos de resultados para um total de 69 linhas (uma classificação é aplicada). Essa consulta acontece muito rapidamente.
Quando adiciono, TOP 1001
o otimizador não usa uma combinação de hash; em vez disso, classifica primeiro os resultados da tabela A (mesma estimativa / real de 19k / 16k) e executa um loop aninhado na tabela B. O número estimado de linhas da tabela B agora é 1, e o estranho é que isso TOP n
afeta diretamente o número estimado de execuções (busca de índice) contra B - parece sempre ser 2n + 1 , ou, no meu caso, 2003. Essa estimativa muda de acordo se eu mudar TOP n
. Obviamente, como essa é uma junção aninhada, o número real de execuções é 16k (o número de linhas da tabela A) e isso torna a consulta mais lenta.
O cenário atual é um pouco mais complexo, mas isso captura a ideia / comportamento básico. Ambas as tabelas são pesquisadas usando pesquisas de índice. Esta é a edição do SQL Server 2008 R2 Enterprise.
ORDER BY
cláusula AdicionandoTOP
alterações onde esse tipo de plano ocorre, mas estou mais preocupado com a forma como isso afeta o número de execuções de buscas de índice na tabela B ... (é claro que as duas podem estar relacionadas - não sei)FAST num_rows
dica de consulta.Respostas:
A maneira como o texto acima é formulado me faz pensar que você pode ter uma imagem mental incorreta de como uma consulta é executada. Um operador em um plano de consulta não é uma etapa (onde o conjunto de resultados completo de uma etapa anterior é avaliado pela próxima.
O SQL Server usa um modelo de execução em pipeline , em que cada operador expõe métodos como Init () , GetRow () e Close () . Como o nome GetRow () sugere, um operador produz uma linha por vez, sob demanda (conforme exigido pelo operador pai). Isso está documentado na referência de Operadores lógicos e físicos dos Manuais Online , com mais detalhes em minha postagem no blog Por que os planos de consulta são executados para trás . Esse modelo de linha por vez é essencial para formar uma intuição sólida para a execução de consultas.
Algumas operações lógicas como
TOP
semi-junções e aFAST n
dica de consulta afetam a maneira como o otimizador de consulta custa alternativas ao plano de execução. A idéia básica é que uma possível forma de plano possa retornar as primeiras n linhas mais rapidamente do que um plano diferente que foi otimizado para retornar todas as linhas.Por exemplo, a junção de loops aninhados indexados geralmente é a maneira mais rápida de retornar um pequeno número de linhas, embora a junção de hash ou mesclagem com varreduras possa ser mais eficiente em conjuntos maiores. A maneira como o otimizador de consulta raciocina sobre essas opções é definindo uma meta de linha em um ponto específico na árvore lógica de operações.
Uma meta de linha modifica a maneira como as alternativas do plano de consulta são avaliadas. A essência disso é que o otimizador começa com o custo de cada operador como se o conjunto de resultados completo fosse necessário, define uma meta de linha no ponto apropriado e depois trabalha de volta na árvore do plano, estimando o número de linhas que ele espera examinar para atingir a meta da linha.
Por exemplo, uma lógica
TOP(10)
define uma meta de linha 10 em um ponto específico da árvore de consultas lógicas. Os custos dos operadores que antecedem o objetivo da linha são modificados para estimar quantas linhas eles precisam produzir para atingir o objetivo da linha. Esse cálculo pode se tornar complexo, portanto, é mais fácil entender tudo isso com um exemplo completo e planos de execução anotados. As metas de linha podem afetar mais do que a escolha do tipo de junção ou se as buscas e pesquisas são preferidas às verificações. Mais detalhes sobre isso aqui .Como sempre, um plano de execução selecionado com base em uma meta de linha está sujeito às habilidades de raciocínio do otimizador e à qualidade das informações fornecidas a ele. Nem todo plano com uma meta de linha produzirá o número necessário de linhas mais rapidamente na prática, mas de acordo com o modelo de custo que produzirá.
Nos casos em que um plano de meta de linha não é mais rápido, geralmente há maneiras de modificar a consulta ou fornecer melhores informações ao otimizador, de modo que o plano naturalmente selecionado seja o melhor. Qual opção é apropriada no seu caso depende dos detalhes do curso. O recurso de meta de linha geralmente é muito eficaz (embora exista um bug a ser observado quando usado em planos de execução paralelos).
Sua consulta e plano específicos podem não ser adequados para uma análise detalhada aqui (por todos os meios, forneça um plano de execução real, se você desejar), mas espero que as idéias descritas aqui permitam que você avance.
fonte
Quando você usa o TOP, o Optimizer vê uma oportunidade de fazer menos trabalho. Se você pedir 10 linhas, há uma boa chance de que ele não precise consumir todo o conjunto. Assim, o operador TOP pode ser empurrado muito mais para a direita. Ele continuará solicitando linhas do próximo operador (à direita) até receber o suficiente.
Você ressalta que, sem TOP, a consulta classifica os dados no final. Se o mecanismo puder saber quantas linhas serão satisfeitas pela junção com antecedência, é possível optar por usar um plano semelhante, posicionando o TOP à esquerda. Porém, com o esforço para fazer uma correspondência de hash ser relativamente alto e, presumivelmente, nenhuma opção para uma junção de mesclagem, o Otimizador pode preferir filtrar o TOP mais para a direita.
Quando a tabela B é consultada, ela está buscando uma única linha de cada vez. É por isso que a estimativa é 1. Ele também pressupõe que encontrará essa linha apenas 50% das vezes. Então, ele acha que precisará de 2n + 1 para encontrá-lo.
fonte
TOP
cláusula? Obrigado pela sua resposta / paciência.