Réponses:
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 leur parviennent avant de pouvoir commencer à traiter ces lignes et à les transmettre en aval, par exemple:
Ils sont appelés bloqueurs ou opérateurs stop and go pour cette raison, et ils sont souvent choisis lorsque l'optimiseur pense qu'il va falloir traiter de nombreuses données pour retrouver vos données.
Il existe d'autres opérateurs capables de commencer la diffusion en continu ou de transmettre immédiatement les lignes trouvées.
Lorsque les requêtes commencent à renvoyer des données immédiatement, mais ne se terminent pas immédiatement, cela indique généralement que l'optimiseur a choisi un plan pour localiser et renvoyer rapidement certaines lignes à l'aide d'opérateurs présentant un coût de démarrage moins élevé.
Cela peut arriver à cause d'objectifs de lignes que vous avez définis ou que vous avez optimisés.
Cela peut également arriver si un mauvais plan est choisi pour une raison quelconque (manque de SARGability, détection de paramètre, statistiques insuffisantes, etc.), mais cela prend plus de temps à comprendre.
Pour plus d'informations, consultez le blog de Rob Farley ici
Et la série de Paul White sur les buts alignés ici , ici , ici et ici .
Il convient également de noter que, si vous parlez de SSMS, les lignes n'apparaissent qu'une fois le tampon complet rempli, et pas seulement à volonté.
Si je comprends ce que vous observez, c'est comment Management Studio rend les lignes, et a peu à voir avec la façon dont SQL Server renvoie les lignes. En fait, lorsque vous renvoyez des résultats volumineux à SSMS et tentez de les restituer dans une grille, SSMS ne peut pas suivre et SQL Server finit par attendre que l'application traite plus de lignes. Dans ce cas, SQL Server accumule les temps d' ASYNC_NETWORK_IO
attente.
Vous pouvez le contrôler quelque peu en utilisant Résultats en texte au lieu de Résultats en grille, car SSMS peut dessiner du texte plus rapidement que des 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. SSMS décide d'écrire les résultats dans ce volet, ce qui dépend du niveau de remplissage de la mémoire tampon de sortie.
Lorsque vous avez plusieurs instructions et que vous souhaitez forcer la mémoire tampon à rendre les résultats de sortie au volet des messages, vous pouvez utiliser une petite astuce d'impression entre les instructions:
RAISERROR('', 0, 1) WITH NOWAIT;
Mais cela n’aidera pas si vous voulez que SSMS rende 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 affichés dans SSMS. Je vois souvent des gens se plaindre du temps qu’il faut pour retourner un million de lignes sur la grille. Qu'est-ce que tout le monde va faire avec un million de lignes dans une grille SSMS, je n'en ai aucune idée.
Certains hacks sont optimaux OPTION (FAST 100)
pour récupérer les 100 premières lignes (ou 100 lignes s’il n’ya pas de lignes extérieures ORDER BY
), mais cela peut entraîner une récupération beaucoup plus lente pour le reste des lignes et un plan plus complexe. inefficace dans son ensemble, ce n’est donc pas vraiment une option de choix, à mon humble avis.
Votre question ne concerne pas SQLServer en tant que tel, mais:
Y a-t-il un moyen de contrôler cela?
Réponse courte :
sqlcmd
au lieu de ssms
ou sqlcmd
-mode dessms
Réponse longue :
Bien sûr! Mais pas un - prob
sqlcmd
ou en sqlcmd
mode en ssms.spid
et obtenez la liste complète des paramètres de session. Comparez avec les paramètres de sqlcmd
session. Si rien ne clique, copiez tous les paramètres de session du profileur dans votre script de requête, exécutez-les en sqlcmd
mode et , en changeant progressivement les paramètres, vous trouverez votre coupable.Bonne chance!
Pour ajouter à la réponse de sp_BlitzErik, prenons l'exemple en utilisant a NOT IN ()
avec une sous-sélection. Afin de déterminer si un élément est dans le résultat de la requête imbriquée, il est (généralement) nécessaire de récupérer le résultat complet.
Donc, un moyen simple, que j'ai trouvé pour améliorer les performances de telles requêtes, est de les réécrire comme LEFT OUTER JOIN
condition avec où la condition de RIGHT
side est nulle (vous pouvez la retourner, bien sûr, mais qui l'utilise RIGHT OUTER JOINS
?). Cela permet aux résultats de commencer à revenir immédiatement.
WHERE t.x IN (<complex SELECT subquery>)
, l'équivalent LEFT JOIN, LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL
la sous-requête doit également être évaluée (le même plan complexe avec le paramètre NOT Version IN).
NOT EXISTS
Oracle NOT IN
dans les requêtes. Mais aujourd'hui, cela doit être considéré comme une erreur dans le générateur de plans