web-dev-qa-db-fra.com

Pourquoi SQL Server renvoie-t-il certaines lignes tout en exécutant la requête, et parfois non?

Il y a des requêtes où lorsque nous frappons "exécuter", il montre quelques lignes et il continue de croître, mais la requête n'est pas encore terminée. Pourtant, parfois, il attend la fin de la requête.

Pourquoi cela arrive-t-il? Y a-t-il un moyen de contrôler cela?

33
Racer SQL

La réponse, comme d'habitude (d'accord, la plupart du temps), réside dans le plan d'exécution.

Certains opérateurs exigent que toutes les lignes les atteignent avant de pouvoir commencer à traiter ces lignes et à les transmettre en aval, par exemple:

  • Hash Join (sur la construction de la table de hachage)
  • Match de hachage
  • Trier (sauf Hash Flow Distinct)

Ils sont soit appelés bloquants, soit opérateurs stop and go à cause de cela, et ils sont souvent choisis lorsque l'optimiseur pense qu'il devra traiter un grand nombre de données pour trouver vos données.

Il existe d'autres opérateurs qui peuvent commencer la diffusion en continu ou transmettre immédiatement les lignes trouvées

  • Boucles imbriquées
  • Fusionner les jointures indexées
  • Agrégats de flux

Lorsque les requêtes commencent à renvoyer des données immédiatement, mais ne se terminent pas immédiatement, cela signifie généralement que l'optimiseur a choisi un plan pour localiser et renvoyer rapidement certaines lignes à l'aide d'opérateurs dont le coût de démarrage est inférieur.

Cela peut se produire en raison d'objectifs de ligne introduits par vous ou par l'optimiseur.

Cela peut également arriver si un mauvais plan est choisi pour une raison quelconque (manque de SARGabilité, reniflement des paramètres, statistiques insuffisantes, etc.), mais cela demande plus de fouilles pour comprendre.

Pour plus d'informations, consultez le blog de Rob Farley ici

Et la série de Paul White sur les objectifs de rang ici , ici , ici , et ici .

Il convient également de noter que, si vous parlez de SSMS, les lignes n'apparaissent qu'une fois qu'un tampon entier a été rempli, et pas seulement bon gré mal gré.

43
Erik Darling

Si je comprends ce que vous observez, voici comment Management Studio rend lignes, et a peu à voir avec la façon dont SQL Server renvoie lignes. En fait, souvent lorsque vous renvoyez des résultats volumineux à SSMS et tentez de les rendre dans une grille, SSMS ne peut pas suivre et SQL Server finit par attendre que l'application traite plus de lignes. Dans ce cas, vous verrez SQL Server accumuler ASYNC_NETWORK_IO Attente.

Vous pouvez le contrôler quelque peu en utilisant Results to Text au lieu de Results to Grid, car SSMS peut dessiner du texte plus rapidement qu'il ne peut dessiner de grilles, mais vous constaterez probablement que cela peut affecter la lisibilité en fonction du nombre de colonnes et des types de données impliqués. Les deux sont affectés par le moment où SSMS décide d'écrire réellement les résultats dans ce volet, ce qui dépend du niveau de remplissage du tampon de sortie.

Lorsque vous avez des instructions multiple et que vous souhaitez forcer le tampon à afficher les résultats de sortie dans le volet des messages, vous pouvez utiliser une petite astuce d'impression entre les instructions:

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

Mais cela n'aidera pas lorsque vous essayez d'obtenir SSMS pour rendre les lignes plus rapidement lorsque toute la sortie provient d'une seule instruction.

Plus directement, vous pouvez le contrôler en limitant le nombre de résultats que vous affichez dans SSMS. Je vois souvent des gens se plaindre du temps qu'il faut pour retourner un million de lignes à la grille. Qu'est-ce que quelqu'un va faire avec un million de lignes dans une grille SSMS, je n'en ai aucune idée.

Il y a quelques hacks comme OPTION (FAST 100) , qui optimisera pour récupérer ces 100 premières lignes (ou n'importe quelle 100 lignes s'il n'y a pas de ORDER BY Externe), mais cela peut se faire au prix d'une récupération beaucoup plus lente pour le reste des lignes et d'un plan qui est globalement plus inefficace, donc ce n'est pas vraiment un go-to option IMHO.

14
Aaron Bertrand

Votre question ne concerne pas SQLServer en soi mais:

  • Serveur SQL
  • réseau
  • SSMS en tant qu'application client

Existe-t-il un moyen de contrôler cela?

Réponse courte:

  1. Essayez sqlcmd au lieu de ssms ou sqlcmd- mode de ssms
  2. Vérifiez vos paramètres de connexion et de session

Réponse longue:

Bien sûr! Mais pas n - prob

  1. Exécutez votre requête avec sqlcmd ou en mode sqlcmd- en ssms.
  2. Si vous souhaitez exclure le rôle du réseau - exécutez votre requête sur le serveur avec une connexion de mémoire partagée.
  3. Si les performances des requêtes ne sont pas satisfaisantes même avec une connexion de mémoire partagée - analysez vos plans d'exécution. Si la requête fonctionne mal via le réseau - appelez votre administrateur réseau pour obtenir de l'aide. Si votre requête fonctionne mal uniquement dans SSMS - lisez la suite.
  4. Maintenant, nous sommes sûrs que les problèmes sont du côté client (ssms dans ce cas). Regardez les paramètres de connexion et de session dans SSMS. Ne croyez pas l'interface ssms et vérifiez avec SQL Profiler: trouvez votre connexion par spid et vous obtenez la liste complète des paramètres de session. Comparer avec les paramètres de la session sqlcmd. Si rien ne clique - copiez tous les paramètres de session du profileur dans votre script de requête, exécutez en mode sqlcmd- et en changeant progressivement les paramètres, vous trouverez votre coupable.

Bonne chance!

1
Alex Yu