Por que o SQL Server retorna algumas linhas enquanto ainda executa a consulta e, às vezes, não?

33

Existem consultas em que, quando clicamos em "executar", mostra algumas linhas e continua crescendo, mas a consulta ainda não acabou. No entanto, às vezes, espera até o final da consulta.

Por que isso acontece? Existe uma maneira de controlar isso?

Racer SQL
fonte

Respostas:

43

A resposta, como sempre (tudo bem, na maioria das vezes), está no plano de execução.

Existem certos operadores que exigem que todas as linhas cheguem a eles antes de começarem a processar essas linhas e transmiti-las a jusante, por exemplo:

  • Hash Join (na construção da tabela de hash)
  • Hash Match
  • Classificar (exceto fluxo de hash distinto)

Eles são chamados de bloqueio ou param e operam por causa disso, e geralmente são escolhidos quando o otimizador acha que precisará processar muitos dados para encontrá-los.

Existem outros operadores que podem iniciar o streaming ou transmitir qualquer linha encontrada imediatamente

  • Loops aninhados
  • Associações de mesclagem suportadas por índice
  • Agregar agregados

Quando as consultas começam a retornar dados imediatamente, mas não terminam imediatamente, geralmente é um sinal de que o otimizador escolheu um plano para localizar e retornar algumas linhas rapidamente usando operadores que têm um custo inicial mais baixo.

Isso pode acontecer devido às metas de linha introduzidas por você ou pelo otimizador.

Isso também pode acontecer se um plano ruim for escolhido por algum motivo (falta de SARGability, detecção de parâmetros, estatísticas insuficientes etc.), mas isso exige mais escavações para descobrir.

Para mais informações, confira o blog de Rob Farley aqui

E a série de Paul White sobre gols em linha aqui , aqui , aqui e aqui .

Deve-se notar também que, se você estiver falando sobre SSMS, as linhas aparecerão apenas quando um buffer inteiro for preenchido, não apenas por vontade própria.

Erik Darling
fonte
14

Se eu entendo o que você está observando, é assim que o Management Studio renderiza linhas e tem pouco a ver com a maneira como o SQL Server retorna linhas. De fato, muitas vezes, quando você retorna grandes resultados ao SSMS e tenta renderizá-los em uma grade, o SSMS não consegue acompanhar e o SQL Server acaba esperando o aplicativo processar mais linhas. Nesse caso, você verá o SQL Server acumulando ASYNC_NETWORK_IOesperas.

Você pode controlá-lo um pouco usando Resultados para Texto em vez de Resultados para Grade, pois o SSMS pode desenhar texto mais rapidamente do que grades, mas provavelmente descobrirá que isso pode afetar a legibilidade, dependendo do número de colunas e dos tipos de dados envolvidos. Ambos são afetados pelo momento em que o SSMS decide realmente gravar os resultados nesse painel, o que depende de quão cheio o buffer de saída está.

Quando você possui várias instruções e deseja forçar o buffer a renderizar resultados de saída no painel de mensagens, pode usar um pequeno truque de impressão entre as instruções:

RAISERROR('', 0, 1) WITH NOWAIT;

Mas isso não ajudará quando você estiver tentando fazer o SSMS renderizar linhas mais rapidamente quando toda a saída vier de uma única instrução.

Mais diretamente, você pode controlá-lo limitando quantos resultados você está renderizando no SSMS. Costumo ver pessoas reclamando quanto tempo leva para retornar um milhão de linhas à grade. O que diabos alguém fará com um milhão de linhas em uma grade do SSMS, não faço ideia.

Existem alguns hacks OPTION (FAST 100), que serão otimizados para recuperar as primeiras 100 linhas (ou quaisquer 100 linhas, se não houver nenhuma externa ORDER BY), mas isso pode custar uma recuperação muito mais lenta do restante das linhas e um plano mais ineficiente em geral, por isso não é realmente uma opção IMHO.

Aaron Bertrand
fonte
1

Sua pergunta não é sobre o SQLServer em si, mas:

  • Servidor SQL
  • rede
  • SSMS como aplicativo cliente

Existe uma maneira de controlar isso?

Resposta curta :

  1. Tente em sqlcmdvez de ssmsou sqlcmd-mode dessms
  2. Verifique suas configurações de conexão e sessão

Resposta longa :

Claro! Mas não um - prob

  1. Execute sua consulta com sqlcmdou no modo sqlcmdem ssms.
  2. Se você deseja excluir a função de rede - execute sua consulta no servidor com conexão de Memória Compartilhada.
  3. Se o desempenho da consulta for insatisfatório, mesmo com a conexão de memória compartilhada - analise seus planos de execução. Se a consulta for ruim pela rede - ligue para o administrador da rede para obter ajuda. Se sua consulta for ruim apenas no SSMS - leia mais.
  4. Agora temos certeza de que os problemas estão no lado do cliente (neste caso, ssms). Veja as configurações de conexão e sessão no SSMS. Não acredite na interface ssms e verifique com o SQL Profiler: encontre sua conexão spide obtenha uma lista completa das configurações da sessão. Compare com as configurações da sqlcmdsessão. Se nada der certo - copie todas as configurações da sessão do criador de perfil para o script de consulta, execute no modo sqlcmde alternando gradualmente as configurações, você encontrará o culpado.

Boa sorte!

Alex Yu
fonte
-2

Para adicionar à resposta de sp_BlitzErik, tome o exemplo usando a NOT IN ()com um sub-select. Para determinar se um item está no resultado da consulta aninhada, é (geralmente) necessário recuperar o resultado inteiro.

Então, uma maneira fácil de encontrar o aprimoramento do desempenho dessas consultas é reescrevê-las como uma LEFT OUTER JOINcondição where onde o RIGHTlado é nulo (você pode inverter, é claro, mas quem usa RIGHT OUTER JOINS?). Isso permite que os resultados comecem a retornar imediatamente.

JimmyJames
fonte
Acho que não. Se as colunas comparadas não forem anuláveis, os resultados deverão ser os mesmos e os planos - geralmente - os mesmos, para as três versões de um antijoin (NOT IN, NOT EXISTS, LEFT JOIN / IS NULL). Não é necessário recuperar o resultado inteiro.
precisa saber é o seguinte
Se a subseleção é realmente complexa, a qual a consulta produzida precisa avaliar toda a subseleção antes de verificar a condição NOT IN WHERE t.x IN (<complex SELECT subquery>), a LEFT JOIN equivalente LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL, a subconsulta também precisará ser avaliada (o mesmo plano complexo com o NOT Versão IN).
precisa saber é o seguinte
@ ypercubeᵀᴹ Funcionou para mim no passado. Já vi consultas que demoram alguns minutos para retornar ao subsegundo.
JimmyJames
@ ypercubeᵀᴹ Eu montei um exemplo simples no Oracle (desculpe, não tenho acesso ao SQLServer no momento) e eles definitivamente tinham planos de explicação diferentes. Talvez não fossem diferenças significativas, mas parecem bem diferentes.
JimmyJames
@ JimmyJames: não é uma maneira simples se você quer um desempenho estável e essas "otimizações" são muito sensíveis à versão do SQLServer. E não cometa erros de apelo ao Oracle (qual versão?). Historicamente, o SQLServer preferia, NOT EXISTSmas o Oracle, NOT INem consultas. Mas hoje ele deve ser considerado como erro no gerador de plano
Alex Yu