Respostas:
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:
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
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.
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_IO
esperas.
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.
Sua pergunta não é sobre o SQLServer em si, mas:
Existe uma maneira de controlar isso?
Resposta curta :
sqlcmd
vez de ssms
ou sqlcmd
-mode dessms
Resposta longa :
Claro! Mas não um - prob
sqlcmd
ou no modo sqlcmd
em ssms.spid
e obtenha uma lista completa das configurações da sessão. Compare com as configurações da sqlcmd
sessã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 sqlcmd
e alternando gradualmente as configurações, você encontrará o culpado.Boa sorte!
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 JOIN
condição where onde o RIGHT
lado é nulo (você pode inverter, é claro, mas quem usa RIGHT OUTER JOINS
?). Isso permite que os resultados comecem a retornar imediatamente.
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).
NOT EXISTS
mas o Oracle, NOT IN
em consultas. Mas hoje ele deve ser considerado como erro no gerador de plano