Große SQL-Server-Ergebnisse mit begrenztem Speicher exportieren
Begrenzen Sie den Speicherverbrauch großer Exporte, untersuchen Sie ASYNC_NETWORK_IO und trennen Sie Datenextraktion von langsamen Downloads.
Eine Abfrage mit Millionen Zeilen ist für den Benutzer nicht fertig, sobald SQL Server die erste Zeile findet. Daten müssen übertragen, dekodiert, formatiert, geschrieben und ausgeliefert werden. Ein schneller Plan kann deshalb mit einem langsamen Export und knappem Anwendungsspeicher zusammenfallen.
Den gesamten Weg messen
Erfassen Sie Zeit bis zur ersten Zeile, Ende des Lesens, Ende des Schreibens, Zeilenzahl, Ausgabebytes und maximalen Anwendungsspeicher. So trennen Sie Serverberechnung, Übertragung und Formatierung. Ein Zeitmesser nur um den ersten Read-Aufruf beschreibt nicht den vollständigen Export.
Während einer langsamen Ausführung zeigt diese Leseabfrage den laufenden Request. Dafür benötigen Sie passende serverweite Diagnoserechte.
SELECT
r.session_id, r.request_id,
r.status, r.wait_type, r.wait_time,
r.total_elapsed_time, r.cpu_time,
r.logical_reads, r.reads, r.row_count,
s.program_name, s.host_name
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s ON s.session_id = r.session_id
WHERE s.is_user_process = 1
AND r.session_id <> @@SPID
ORDER BY r.total_elapsed_time DESC;
Wiederholtes ASYNC_NETWORK_IO zeigt, dass der Server auf Ergebnisabnahme oder entsprechenden Netzwerkfortschritt wartet. Es beweist keinen Netzwerkdefekt. Ein Client, der jede Zeile komprimiert, protokolliert oder per HTTP weitersendet, kann auch bei gesunder Verbindung zu langsam lesen. Vergleichen Sie CPU, Schreibdurchsatz und Netzwerkmessungen.
Reduzieren Sie unnötige Daten an der Quelle. Wählen Sie benötigte Spalten und sinnvolle Filter oder Aggregationen in SQL. Eine später verworfene große Beschreibung verursacht trotzdem Übertragung und Dekodierung. Erhalten Sie dabei die Semantik: Ein Detailbericht darf nicht allein wegen geringerer Größe zu einer Summenliste werden.
Speicher begrenzen und Rückstau verstehen
Ein vorwärts lesender Reader vermeidet eine vollständige Ergebnissammlung im Speicher. Für große Binär- oder Textspalten ermöglichen SequentialAccess und passende SqlClient-Stream-APIs schrittweises Lesen. Beachten Sie die erforderliche Spaltenreihenfolge und konsumieren Sie gestreamte Werte vor späteren Feldern.
Asynchrone Ein- und Ausgabe begrenzt Speicher nicht automatisch. Eine Schleife, die pro Zeile einen Task startet und alle Aufgaben oder Zeilen speichert, wächst weiterhin mit der Datenmenge. Verwenden Sie einen begrenzten Kanal oder feste Batches zwischen Extraktion und Verarbeitung sowie eine feste Workerzahl.
Wenn die Folgestufe langsamer wird, muss der Puffer weiteres Wachstum stoppen. Dieser Rückstau hält jedoch Reader und Verbindung offen. Je nach Abfrage und Isolation kann lange Ausführung Sperren verlängern, Versionen erhalten oder einen Memory Grant belegen. Alles zunächst in den Speicher zu laden verkürzt die Readerdauer, belastet aber den Client.
Für langsame Benutzerdownloads kann ein Hintergrundjob zunächst eine temporäre Datei in kontrollierten Speicher schreiben. Danach schließt er den Reader, bevor der Benutzer herunterlädt. Geben Sie die fertige Datei erst nach Erfolg frei und speichern Sie Zeilenzahl, Größe und möglichst Prüfsumme. Eine abgebrochene Teildatei darf nicht als vollständiges Ergebnis erscheinen.
Konsistenz und Abschluss festlegen
Definieren Sie, welchen Datenzeitpunkt der Export darstellt. Mehrere getrennte Batches unter gewöhnlichem Read Committed bilden nicht automatisch einen gemeinsamen Snapshot. Zwischen ihnen können sich Zeilen ändern. Eine lange Snapshot-Transaktion bietet andere Semantik, kann aber Versionen lange aufbewahren. Wählen und messen Sie diesen Vertrag bewusst.
Benötigt das Dateiformat reproduzierbare Reihenfolge oder Wiederaufnahme, verwenden Sie eine stabile Sortierung. ORDER BY kann zusätzliche Serverarbeit verursachen und gehört in den Test. Ein oberer Schlüsselwert beweist nicht, dass alle Werte während der Extraktion unverändert bleiben.
Geben Sie Abbruchsignale weiter und entsorgen Sie Reader, Command und eigene Verbindung auf jedem Fehlerpfad. Beenden Sie eine dem Job gehörende Transaktion ausdrücklich. Testen Sie Abbruch durch den Empfänger, vollen Ausgabespeicher, späten Konvertierungsfehler und Wiederholung derselben Exportanforderung.
Unterscheiden Sie abschließend Joberfolg und erfolgreichen Download. Eine gültige Datei kann bereits existieren, obwohl die Benutzerverbindung abbrach. Ihre erneute Bereitstellung ist oft günstiger und zuverlässiger als eine neue Datenbankabfrage. Ein belastbarer Export verbindet begrenzte Ressourcen mit einem überprüfbaren Vollständigkeitssignal.
Technische Referenzen: Microsoft Learn: ASYNC_NETWORK_IO · Microsoft Learn: SqlClient streaming.