Wir haben eine Datenbank für ein Produkt, das schwer zu beschreiben ist. Wir haben gerade einen neuen Server mit einer SSD gekauft, um zu helfen. Zu unserer Überraschung waren die Einfügungen nicht schneller als auf unserer alten Maschine mit viel langsamerer Lagerung. Beim Benchmarking haben wir festgestellt, dass die E / A-Rate des SQL Server-Prozesses sehr niedrig war.
Zum Beispiel habe ich das Skript auf dieser Seite ausgeführt , mit der Ausnahme, dass ich ein BEGIN TRAN und ein COMMIT um die Schleife hinzugefügt habe. Bestenfalls konnte ich sehen, dass die Festplattenauslastung 7 MB / s erreichte, während die CPU 5% kaum berührte. Auf dem Server sind 64 GB installiert, und es wird 10 verwendet. Die Gesamtlaufzeit betrug 2 Minuten und 15 Sekunden für den ersten Aufruf bis zu einer Minute für nachfolgende Aufrufe. Die Datenbank wird einfach wiederhergestellt und war während des Tests inaktiv. Ich ließ den Tisch zwischen jedem Anruf fallen.
Warum ist so ein einfaches Skript so langsam? Die Hardware wird kaum genutzt. Sowohl dedizierte Festplatten-Benchmarking-Tools als auch SQLIO zeigen an, dass die SSD sowohl beim Lesen als auch beim Schreiben mit Geschwindigkeiten von über 500 MBit / s ordnungsgemäß funktioniert. Ich verstehe, dass zufällige Schreibvorgänge langsamer sind als sequentielle Schreibvorgänge, aber ich würde erwarten, dass eine einfache Einfügung in eine Tabelle ohne gruppierte Indizierung viel schneller ist.
Letztendlich ist unser Szenario viel komplexer, aber ich habe das Gefühl, dass ich zuerst einen einfachen Fall verstehen muss. Kurz gesagt, unsere Anwendung löscht alte Daten, kopiert neue Daten mithilfe von SqlBulkCopy in Staging-Tabellen, filtert sie und kopiert die Daten schließlich mithilfe von MERGE und / oder INSERT INTO (je nach Fall) in die endgültigen Tabellen.
-> BEARBEITEN 1: Ich habe die Prozedur von Martin Smith befolgt und folgendes Ergebnis erhalten:
[Wait Type] [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO 5008 46735 46587 148
LOGBUFFER 901 5994 5977 17
PAGELATCH_UP 40 866 865 1
SOS_SCHEDULER_YIELD 53279 219 121 98
WRITELOG 5 145 145 0
PAGEIOLATCH_UP 4 58 58 0
LATCH_SH 5 0 0 0
Ich finde es seltsam, dass NETWORK_IO die meiste Zeit in Anspruch nimmt, wenn man bedenkt, dass kein Ergebnis angezeigt und keine Daten an einen anderen Ort als in die SQL-Dateien übertragen werden müssen. Umfasst der Typ NETWORK_IO alle E / A?
-> BEARBEITEN 2: Ich habe eine 20-GB-RAM-Disk erstellt und von dort aus eine Datenbank gemountet. Die beste Zeit, die ich auf der SSD hatte, war 48 Sekunden, mit der RAM-Disk ging es auf 37 Sekunden zurück. NETWORK_IO ist immer noch das größte Warten. Die maximale Schreibgeschwindigkeit auf die RAM-Disk betrug etwa 250 MB / s, während sie mehrere Gigabyte pro Sekunde verarbeiten kann. Es wurde immer noch nicht viel CPU verbraucht. Was hält also SQL davon ab?
SET NOCOUNT ON
.NETWORK_IO
könnte von der 3 Millionen „1 Zeile (n) betroffen“ sein , um Nachrichten zurück gesendet werden. Haben Sie versuchtSET NOCOUNT ON
, dem Skript etwas hinzuzufügen ?EE_WaitStats*.xel
sodass alte Ihre Ergebnisse verunreinigen.Antworten:
Ich weiß, dass es eine alte Frage ist, aber dies könnte den Suchenden trotzdem helfen, und es ist ein Problem, das hin und wieder auftaucht.
Der Hauptgrund, warum Sie eine Leistungsobergrenze erreichen, ohne einen Ressourcenengpass zu bemerken, liegt darin, dass Sie die Grenze dessen erreicht haben, was innerhalb eines einzelnen Sitzungsthreads verarbeitet werden kann. Die Schleife wird nicht parallel verarbeitet, aber alle Einfügungen erfolgen seriell.
In meinem Fall dauert das Einfügen von 3 Millionen Zeilen 36 Sekunden. Das bedeutet 36/30000000 = 0,000012 Sekunden pro Zeile. Das geht ziemlich schnell. Auf meinem System sind lediglich 0.000012 erforderlich, um alle erforderlichen Schritte auszuführen.
Die einzige Möglichkeit, dies schneller zu erledigen, besteht darin, eine zweite Sitzung parallel zu starten.
Wenn ich 2 Sessions parallel starte, machen beide 15 Millionen Inserts. Beide sind in 18 Sekunden fertig. Ich könnte mehr skalieren, aber mein aktuelles Test-Setup erreicht bei zwei parallelen Sessions 95% CPU. Wenn ich also 3 mache, würde das die Ergebnisse verzerren, da ich auf einen CPU-Engpass stoßen würde.
Wenn ich zwei parallele Sitzungen beginne, in denen jeweils drei Millionen Zeilen eingefügt werden, werden beide in 39 Sekunden beendet. Das sind jetzt 6 Millionen Zeilen in 39 Sekunden.
Okay, das lässt uns immer noch mit der NETWORK_IO-Wartezeit auftauchen.
Die NETWORK_IO-Wartezeiten werden durch die Tatsache hinzugefügt, dass Sie erweiterte Ereignisse verwenden, um sie zu verfolgen. In meinem Fall dauert der Einsatz 36 Sekunden (im Durchschnitt). Bei Verwendung der erweiterten Ereignismethode (vom Link oben im allerersten Kommentar) wird Folgendes registriert:
Sie können sehen, dass 68 Sekunden von NETWORK_IO registriert sind. Da es sich bei der Insert-Schleife jedoch um eine einzelne Thread-Aktion handelt, die 36 Sekunden dauerte, kann dies nicht der Fall sein. (Ja, es werden mehrere Threads verwendet, aber die Vorgänge sind seriell, niemals parallel, sodass Sie nicht mehr Wartezeit als die Gesamtdauer der Abfrage benötigen können.)
Wenn ich keine erweiterten Ereignisse verwende, sondern nur die Wartestatistik-DMVs auf einer stillen Instanz (wobei nur ich die Einfügung ausführe), erhalte ich Folgendes:
Das NETWORK_IO, das Sie im erweiterten Ereignisprotokoll sehen, war also nicht mit Ihrer Einfügeschleife verknüpft. (Wenn Sie nocount nicht einschalten würden, hätten Sie massive asynchrone Netzwerk-E / A-Wartezeiten, +1 Martin)
Ich weiß jedoch nicht, warum das NETWORK_IO in der erweiterten Ereignisablaufverfolgung angezeigt wird. Sicher, das Ausschreiben der Ereignisse in eine asynchrone Datei akkumuliert ASYNC_NETWORK_IO, aber dies geschieht mit Sicherheit auf einer anderen SPID als der, nach der wir filtern. Ich könnte dies selbst als neue Frage stellen.)
quelle
Typischerweise beginnen Sie , indem Sie auf
sys.dm_exec_requests
, die speziell auf diewait_time
,wait_type
undwait_resource
für Ihre INSERT Anfrage (n). Dies gibt einen klaren Hinweis darauf, was Ihr INSERT blockiert. Die Ergebnisse zeigen an, ob es sich um Sperrenkonflikte, Dateiwachstumsereignisse, Wartezeiten beim Löschen von Protokollen, Zuordnungskonflikte (manifestiert sich als PFS-Seitenzwischenspeicherkonflikte) usw. usw. handelt. Aktualisieren Sie Ihre Frage nach der Messung entsprechend. Ich rate Ihnen dringend, jetzt aufzuhören und die Methoden zur Fehlerbehebung bei Warteschlangen und Warteschlangen zu lesen, bevor Sie fortfahren.quelle
Ich habe das Testskript auf der Seite ausgeführt, die im OP mit BEGIN TRAN / COMMIT um die Schleife verknüpft ist. Auf meinem Computer dauerte es 1:28, bis der erste Vorgang abgeschlossen war.
Dann habe ich diese beiden Befehle außerhalb der Schleife verschoben:
Es war in 28 Sekunden fertig.
Ich weiß nicht genau, was passiert, aber ich vermute, dass der
RAND()
Code eine Art Schlaf enthält, vielleicht als Teil des Algorithmus, mit dem sie Entropie erzeugen (bessere Zufallszahlen).FWIW, SSDs sind nicht immer die beste Technologie für schreiblastige Apps. Stellen Sie für eine optimale Leistung sicher, dass sich Ihr DB-Protokoll auf einem anderen Laufwerksbuchstaben als die DB-Daten befindet, die Protokolldatei auf ihre maximale Größe vorab vergrößert ist und das Protokoll niemals abgeschnitten wird.
quelle
Eine andere DMV, die ich verwende, um Langsamkeit zu identifizieren, ist sys.dm_os_waiting_tasks . Wenn Ihre Abfrage nicht CPU-intensiv ist, finden Sie in dieser DMV weitere Informationen zu den Wartezeiten.
quelle
Ich überprüfe die Liste der Warteereignisse für SQL 2008 und sehe NETWORK_IO nicht aufgelistet: http://technet.microsoft.com/en-us/library/ms179984(v=sql.100).aspx
Ich dachte, dass NETWORK_IO jetzt nur als ASYNC_NETWORK_IO aufgeführt ist, also wollte ich fragen, ob Sie Ihre SQL-Version erneut überprüfen können, weil ich einfach gespannt bin, wie / warum dieses Warteereignis für diese Version angezeigt wird.
Was die Netzwerkwartezeit angeht, so kann dies durchaus vorkommen, auch wenn Sie auf einem eigenständigen Server arbeiten. Haben Sie die Einstellungen für Ihre Netzwerkkarten überprüft? Ich frage mich, ob sie ein Problem sind.
Letztendlich sind nur wenige Ressourcenengpässe möglich: Arbeitsspeicher, CPU, Festplatten-E / A, Netzwerk und Sperren. Sie haben angegeben, dass CPU und E / A nicht das Problem sind, und Sie haben ein Warteereignis von NETWORK_IO. Ich schlage daher vor, dass Sie sich zuerst diese NIC-Karten ansehen.
quelle
NETWORK_IO
wird angezeigt, weil das OP erweiterte Ereignisse verwendet. Es wurde nie aktualisiert insys.dm_xe_map_values