Eu tenho uma visão, complicated_view
-- existem algumas junções e cláusulas where. Agora,
select * from complicated_view (9000 records)
é mais rápido, muito mais rápido , do que
select top 500 * from complicated_view
Estamos falando de 19 segundos contra mais de 5 minutos.
A primeira consulta retorna todos os 9.000 registros. Como só pegar o top 500 é ridiculamente mais longo?
Obviamente, vou examinar os planos de execução aqui ---- mas assim que descobrir por que o SQL Server está executando o "top 500" de maneira abaixo do ideal, como posso dizer a ele para executar o plano de maneira rápida, como tomar a mesa cheia?
Claro, eu posso ter que reescrever a visão inteiramente --- mas muito estranho.
Basicamente, estou conectando esta tabela de dados a um software de terceiros que pré-verifica tabelas com uma select top 500 *
consulta padrão que não pode ser modificada. Então, além de despejar essa visão em uma tabela real (bastante desleixada) - também não consigo contornar o adendo "top 500".
Este é o SQL Server 2012.
EDIT: Discordo do sinalizador duplicado. A outra pergunta, o top foi mais rápido que todos. Este seria o comportamento ESPERADO, retornando menos linhas. Meu caso é o contrário. Além disso, meu entendimento é que o Top 100 é um algoritmo diferente do Top 100+. Eu nem acho que a pergunta duplicada tem a resposta correta. Ou seja, a consulta TOP X ordenará tabelas potencialmente massivas muito cedo, não DEPOIS de serem agregadas/filtradas/etc. O porquê é um mistério, mas o como está claramente lá.
Adicionar uma
TOP
cláusula a uma consulta introduz um objetivo de linha à consulta. O otimizador de consulta tentará usar o fato de não precisar retornar todas as linhas para criar um plano de consulta mais eficiente. A meta de linha pode fazer com que o custo de alguns operadores seja reduzido. A otimização de meta de linha pode funcionar contra o sintonizador de consulta devido a limitações de modelo ou informações incompletas em objetos de estatísticas. Abaixo, tenho uma demonstração em relação a uma visualização simples para a qual a adiçãoTOP 500
degrada o desempenho.Primeiro insira apenas números inteiros ímpares em uma tabela. Observe que estou reunindo estatísticas completas no final.
Em seguida, insira apenas números inteiros pares em uma tabela diferente. Estou fazendo algumas coisas com valores repetidos e tamanho de linha para fazer a demonstração funcionar. Eu ainda atualizo as estatísticas na íntegra no final.
Aqui está a definição de visualização:
Considere a seguinte consulta:
Veja como é o plano de consulta:
Uma limitação de custo faz com que a varredura completa da
EVEN
tabela no lado interno da junção de loop aninhado tenha um custo relativo baixo. Com base em como construí os dados, sabemos que o otimizador precisará verificar 500 * 100.000 = 50 milhões de linhas daEVEN
tabela para retornar as primeiras 500 linhas ao cliente. Isso é realmente o que acontece, e a consulta leva cerca de 16 segundos para ser executada na minha máquina:A remoção da
TOP
cláusula da consulta fornece um plano diferente e mais eficiente :Esta consulta é executada em menos de meio segundo na minha máquina. Apenas 100.000 linhas são lidas da
EVEN
tabela.Para o SQL Server 2016 e versões posteriores, você pode contornar esse problema sem alterar a definição da exibição adicionando
OPTION (USE HINT('DISABLE_OPTIMIZER_ROWGOAL'))
à consulta. Essa dica desativa a otimização da meta de linha no nível da consulta. Para o SQL Server 2012, você pode usar o sinalizador de rastreamento 4138 no nível de consulta viaOPTION (QUERYTRACEON 4138)
, mas isso requer SA.Não posso dizer nada sobre sua consulta em particular sem ver os planos de consulta, mas espero que este exemplo ilustre o ponto geral.