Warum gibt SQL Server einige Zeilen zurück, während die Abfrage ausgeführt wird, und manchmal nicht?

33

Es gibt Abfragen, bei denen, wenn wir auf "Ausführen" klicken, einige Zeilen angezeigt werden und die Anzahl wächst, die Abfrage jedoch noch nicht beendet ist. Manchmal wartet es jedoch bis zum Ende der Abfrage.

Warum passiert das? Gibt es eine Möglichkeit, dies zu kontrollieren?

Racer SQL
quelle

Antworten:

43

Die Antwort liegt, wie immer (meistens), im Ausführungsplan.

Es gibt bestimmte Operatoren, bei denen alle Zeilen ankommen müssen, bevor sie diese Zeilen verarbeiten und weiterleiten können. Beispiel:

  • Hash Join (beim Erstellen der Hash-Tabelle)
  • Hash Match
  • Sortieren (außer Hash Flow Distinct)

Sie werden entweder als Blockierungs- oder Stop-and-Go-Operatoren bezeichnet. Sie werden häufig ausgewählt, wenn das Optimierungsprogramm denkt, dass es eine ganze Menge Daten verarbeiten muss, um Ihre Daten zu finden.

Es gibt andere Operatoren, die in der Lage sind, Streams zu starten oder gefundene Zeilen sofort weiterzuleiten

  • Verschachtelte Schleifen
  • Index unterstützte Merge Joins
  • Aggregate streamen

Wenn Abfragen beginnen, Daten sofort zurückzugeben, aber nicht sofort beendet werden, ist dies in der Regel ein Zeichen dafür, dass das Optimierungsprogramm einen Plan zum schnellen Suchen und Zurückgeben einiger Zeilen mithilfe von Operatoren mit geringeren Startkosten ausgewählt hat.

Dies kann aufgrund von Zeilenzielen geschehen, die entweder von Ihnen oder vom Optimierer eingeführt wurden.

Es kann auch vorkommen, dass aus irgendeinem Grund ein falscher Plan ausgewählt wird (mangelnde SARGability, Parameter-Sniffing, unzureichende Statistiken usw.), dies erfordert jedoch mehr Zeit, um dies herauszufinden.

Weitere Informationen finden Sie in Rob Farleys Blog hier

Und Paul Whites Serie über Reihentore hier , hier , hier und hier .

Wenn Sie von SSMS sprechen, sollten Sie auch beachten, dass Zeilen nur dann angezeigt werden, wenn ein ganzer Puffer gefüllt wurde, und nicht nur zufällig.

Erik Darling
quelle
14

Wenn ich verstehe, was Sie beobachten, ist dies, wie Management Studio Zeilen rendert , und hat wenig damit zu tun, wie SQL Server Zeilen zurückgibt . Tatsächlich kann SSMS oft nicht mithalten, wenn Sie große Ergebnisse an SSMS zurückgeben und versuchen, sie in einem Raster zu rendern, und SQL Server wartet darauf, dass die App weitere Zeilen verarbeitet. In diesem Fall wird SQL Server ASYNC_NETWORK_IOWartezeiten ansammeln .

Sie können dies ein wenig steuern, indem Sie "Ergebnisse in Text" anstelle von "Ergebnisse in Raster" verwenden, da SSMS Text schneller zeichnen kann als Gitter. Dies kann sich jedoch wahrscheinlich auf die Lesbarkeit auswirken, abhängig von der Anzahl der Spalten und den beteiligten Datentypen. Beides wird beeinflusst, wenn SSMS beschließt, die Ergebnisse tatsächlich in diesen Bereich zu schreiben. Dies hängt davon ab, wie voll der Ausgabepuffer ist.

Wenn Sie über mehrere Anweisungen verfügen und den Puffer zwingen möchten, die Ausgabeergebnisse im Nachrichtenfenster wiederzugeben, können Sie zwischen den Anweisungen einen kleinen Drucktrick anwenden:

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

Dies hilft jedoch nicht, wenn Sie SSMS dazu bringen möchten, Zeilen schneller zu rendern, wenn die gesamte Ausgabe von einer einzelnen Anweisung stammt.

Sie können dies direkt steuern, indem Sie die Anzahl der in SSMS gerenderten Ergebnisse begrenzen. Ich sehe oft Leute, die sich darüber beschweren, wie lange es dauert, bis eine Million Zeilen wieder im Raster sind. Was um alles in der Welt jeder mit einer Million Zeilen in einem SSMS-Grid machen wird, weiß ich nicht.

Es gibt einige Hacks wie OPTION (FAST 100), die für das Abrufen dieser ersten 100 Zeilen (oder aller 100 Zeilen, wenn es keine äußeren gibt ORDER BY) optimiert sind , aber dies kann zu Lasten eines viel langsameren Abrufs für den Rest der Zeilen und eines Plans gehen, der mehr ist Insgesamt ineffizient, ist also meiner Meinung nach keine gute Wahl.

Aaron Bertrand
quelle
1

Ihre Frage bezieht sich nicht auf SQLServer per se, sondern auf:

  • SQL Server
  • Netzwerk
  • SSMS als Client-Anwendung

Gibt es eine Möglichkeit, dies zu kontrollieren?

Kurze Antwort :

  1. Versuchen Sie es sqlcmdanstelle von ssmsodersqlcmd -Modus vonssms
  2. Überprüfen Sie Ihre Verbindungs- und Sitzungseinstellungen

Lange Antwort :

Na sicher! Aber nicht eins - wahrscheinlich

  1. Führen Sie Ihre Abfrage mit sqlcmdoder in aussqlcmd im -Modus in ssms aus.
  2. Wenn Sie die Rolle des Netzwerks ausschließen möchten, führen Sie Ihre Abfrage auf einem Server mit Shared Memory-Verbindung aus.
  3. Wenn die Abfrageleistung auch mit einer Shared Memory-Verbindung nicht zufriedenstellend ist, analysieren Sie Ihre Ausführungspläne. Wenn die Netzwerkabfrage nicht funktioniert, wenden Sie sich an Ihren Netzwerkadministrator. Wenn Ihre Abfrage nur in SSMS fehlerhaft ist, lesen Sie weiter.
  4. Jetzt sind wir sicher, dass Probleme auf der Clientseite liegen (in diesem Fall ssms). Überprüfen Sie die Verbindungs- und Sitzungseinstellungen in SSMS. Glauben Sie nicht an die ssms-Schnittstelle und wenden Sie sich an SQL Profiler: Suchen Sie nach Ihrer Verbindung, spidund Sie erhalten eine vollständige Liste der Sitzungseinstellungen. Vergleiche mit den Einstellungen der sqlcmdSitzung. Wenn nichts klickt - kopieren Sie alle Sitzungseinstellungen aus dem Profiler in Ihr Abfrageskript, führen Sie im sqlcmd-Modus aus und ändern Sie die Einstellungen nach und nach, um den Schuldigen zu finden.

Viel Glück!

Alex Yu
quelle
-2

Um die Antwort von sp_BlitzErik zu ergänzen, verwenden Sie das Beispiel a NOT IN ()mit einer Unterauswahl. Um festzustellen, ob sich ein Element im Ergebnis der verschachtelten Abfrage befindet, muss (im Allgemeinen) das gesamte Ergebnis abgerufen werden.

Eine einfache Möglichkeit, die Leistung solcher Abfragen zu verbessern, besteht darin, sie als " LEFT OUTER JOINwhere condition for RIGHTside" (null) umzuschreiben (Sie könnten es natürlich umdrehen, aber wer verwendet es RIGHT OUTER JOINS?). Auf diese Weise können die Ergebnisse sofort wieder angezeigt werden.

JimmyJames
quelle
Ich glaube nicht. Wenn die verglichenen Spalten nicht nullwertfähig sind, sollten die Ergebnisse und die Pläne für die drei Versionen eines Antijoin (NOT IN, NOT EXISTS, LEFT JOIN / IS NULL) identisch sein. Es ist nicht erforderlich, das gesamte Ergebnis abzurufen.
ypercubeᵀᴹ
Wenn die Unterauswahl wirklich komplex ist und die erzeugte Abfrage die gesamte Unterauswahl auswerten muss, bevor die NOT IN-Bedingung, WHERE t.x IN (<complex SELECT subquery>)der entsprechende LEFT JOIN, überprüft wird LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL, muss auch die Unterabfrage ausgewertet werden (also derselbe komplexe Plan mit dem NOT IN-Version).
ypercubeᵀᴹ
@ ypercubeᵀᴹ Es hat in der Vergangenheit für mich funktioniert. Ich habe gesehen, wie Abfragen von Minuten bis zur nächsten Sekunde zurückgingen.
JimmyJames
@ ypercubeᵀᴹ Ich habe in Oracle ein einfaches Beispiel zusammengestellt (sorry, ich habe momentan keinen Zugriff auf SQLServer) und sie hatten definitiv unterschiedliche EXPLAIN-Pläne. Vielleicht waren sie keine bedeutenden Unterschiede, aber sie sehen ziemlich unterschiedlich aus.
JimmyJames
@JimmyJames: Es ist keine einfache Möglichkeit, um eine stabile Leistung zu erzielen, und solche "Optimierungen" sind für die SQLServer-Version sehr heikel. Und machen Sie keine Fehler, die Oracle ansprechen (welche Version?). Historisch bevorzugte SQLServer NOT EXISTSaber Oracle NOT INbei Abfragen. Aber heute muss es als Fehler im Plan Generator betrachtet werden
Alex Yu