it-swarm-eu.dev

SQL: Was verlangsamt INSERTs, wenn nicht CPU oder IO?

Wir haben eine Datenbank für ein Produkt, das schreibintensiv ist. Wir haben gerade einen neuen Server mit einer SSD gekauft, um zu helfen. Zu unserer Überraschung waren die Einfügungen nicht schneller als bei unserer alten Maschine mit viel langsamerer Lagerung. Beim Benchmarking haben wir festgestellt, dass die vom SQL Server-Prozess angezeigte Rate IO] sehr niedrig war.

Zum Beispiel habe ich das Skript ausgeführt, das auf diese Seite gefunden wurde, außer dass ich ein BEGIN TRAN und COMMIT um die Schleife hinzugefügt habe. Bestenfalls konnte ich sehen, dass die Festplattenauslastung 7 MBit/s erreichte, während die CPU kaum 5% erreichte. Der Server hat 64 GB installiert und verwendet 10. Die Gesamtlaufzeit betrug 2 Minuten 15 Sekunden für den ersten Anruf bis zu etwa 1 Minute für nachfolgende Anrufe. Die Datenbank befindet sich in einer einfachen Wiederherstellung und war während des Tests inaktiv. Ich habe den Tisch zwischen jedem Anruf fallen lassen.

Warum ist ein so einfaches Skript so langsam? Die Hardware wird kaum benutzt. Sowohl dedizierte Festplatten-Benchmarking-Tools als auch SQLIO zeigen an, dass die SSD beim Lesen und Schreiben mit einer Geschwindigkeit 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 wie diese in eine Tabelle ohne Clustered-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 dann mithilfe von SqlBulkCopy neue Daten in Staging-Tabellen, führt eine Filterung durch und verwendet schließlich je nach Fall MERGE und/oder INSERT INTO, um die Daten in die endgültigen Tabellen zu kopieren.

-> EDIT 1: Ich habe das von Martin Smith verknüpfte Verfahren befolgt und das folgende 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 irgendwo anders als in die SQL-Dateien übertragen werden müssen. Enthält der Typ NETWORK_IO alle E/A?

-> EDIT 2: Ich habe eine 20Gb RAM -Diskette erstellt und von dort aus eine Datenbank gemountet. Die beste Zeit, die ich auf der SSD hatte, war 48s mit dem RAM = Festplatte ging auf 37 Sekunden zurück. NETWORK_IO ist immer noch die größte Wartezeit. Die maximale Schreibgeschwindigkeit auf die Festplatte RAM Festplatte betrug ca. 250 MBit/s, während sie mehrere Gigabyte pro Sekunde ausführen kann verbrauchte nicht viel CPU, also was hält SQL auf?

20
Djof

Ich weiß, dass es eine alte Frage ist, aber dies könnte den Suchenden immer noch helfen und es ist ein Problem, das hin und wieder auftaucht.

Der Hauptgrund, warum Sie eine Leistungsobergrenze erreichen, ohne dass ein Ressourcenengpass auftritt, liegt darin, dass Sie die Grenze für die Verarbeitung innerhalb eines einzelnen Sitzungsthreads erreicht haben. Die Schleife wird nicht parallel verarbeitet, aber alle Einfügungen werden seriell ausgeführt.

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 dauert es einfach 0,000012, 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 Sitzungen parallel starte, machen beide 15 Millionen Einfügungen. Beide sind in 18 Sekunden fertig. Ich könnte mehr skalieren, aber mein aktuelles Test-Setup erreicht 95% CPU bei zwei parallelen Sitzungen, sodass 3 die Ergebnisse verzerren würde, da ich auf einen CPU-Engpass stoßen würde.

Wenn ich zwei parallele Sitzungen starte, in denen beide 3 Millionen Zeilen einfügen, werden beide in 39 Sekunden beendet. Das sind jetzt 6 Millionen Zeilen in 39 Sekunden.

Okay, das lässt uns immer noch mit dem NETWORK_IO warten.

Die NETWORK_IO-Wartezeiten werden durch die Tatsache hinzugefügt, dass Sie erweiterte Ereignisse verwenden, um sie zu verfolgen. In meinem Fall dauert das Einfügen 36 Sekunden (im Durchschnitt). Bei Verwendung der erweiterten Ereignismethode (über den Link oben im allerersten Kommentar) wird Folgendes registriert:

Wait Type             Wait Count  Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms)
NETWORK_IO            3455        68808                68802                         6
PAGEIOLATCH_SH        3           64                   64                            0
PAGEIOLATCH_UP        12          58                   58                            0
WRITE_COMPLETION      8           15                   15                            0
WRITELOG              3           9                    9                             0
PAGELATCH_UP          2           4                    4                             0
SOS_SCHEDULER_YIELD   32277       1                    0                             1
IO_COMPLETION         8           0                    0                             0
LATCH_SH              3           0                    0                             0
LOGBUFFER             1           0                    0                             0

Sie können sehen, dass 68 Sekunden von NETWORK_IO registriert sind. Da es sich bei der Einfügeschleife jedoch um eine einzelne Thread-Aktion handelt, die 36 Sekunden dauerte, kann dies nicht sein. (Ja, es werden mehrere Threads verwendet, aber die Vorgänge sind seriell und niemals parallel, sodass Sie nicht mehr Wartezeit als die Gesamtdauer der Abfrage berechnen 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:

Wait Type                   Wait Count  Total Wait Time (ms)  Total Resource Wait Time (ms) Signal Resource Wait Time (ms)
SOS_SCHEDULER_YIELD             8873                 0.21                                    0.01                                    0.20
PAGEIOLATCH_UP                  3                    0.02                                    0.02                                    0.00
PREEMPTIVE_OS_AUTHENTICATIONOPS 17                   0.02                                    0.02                                    0.00
PAGEIOLATCH_SH                  1                    0.00                                    0.00                                    0.00

Das NETWORK_IO, das Sie im erweiterten Ereignisprotokoll gesehen haben, war also nicht mit Ihrer Einfügeschleife verbunden. (Wenn Sie nocount nicht einschalten würden, hätten Sie ein massives asynchrones Netzwerk IO wartet, +1 Martin)

Ich weiß jedoch nicht, warum das NETWORK_IO in der erweiterten Ereignisablaufverfolgung angezeigt wird. Sicher, das Schreiben der Ereignisse in ein asynchrones Dateiziel sammelt ASYNC_NETWORK_IO, aber dies geschieht sicherlich alles auf einer anderen SPID als der, nach der wir filtern. Ich könnte dies selbst als neue Frage stellen.

10
Edward Dortland

Normalerweise beginnen Sie mit einem Blick auf sys.dm_exec_requests , speziell am wait_time, wait_type und wait_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 Sperrkonflikte, Dateiwachstumsereignisse, Wartezeiten beim Löschen von Protokollen, Zuordnungskonflikte (manifestiert sich als PFS-Seitenverriegelungskonflikte) usw. usw. usw. handelt. Aktualisieren Sie Ihre Frage nach dem Messen entsprechend. Ich empfehle Ihnen dringend, jetzt anzuhalten und die Waits and Queues Fehlerbehebungsmethode zu lesen, bevor Sie fortfahren.

9
Remus Rusanu

Ich habe das Testskript auf der Seite ausgeführt, die im OP mit dem BEGIN TRAN/COMMIT um die Schleife verknüpft ist. Auf meinem Computer dauerte das erste Mal 1:28.

Dann habe ich diese beiden Befehle außerhalb der Schleife verschoben:

SELECT @Random = ROUND(((@Upper - @Lower -1) * Rand() + @Lower), 0)
SET @InsertDate = DATEADD(dd, @Random, GETDATE())

Es war in 28 Sekunden erledigt.

Ich weiß nicht genau, was passiert, aber ich vermute, dass der Code Rand() möglicherweise einen Schlaf enthält, möglicherweise als Teil des Algorithmus, mit dem sie Entropie erzeugen (besser zufällig) Zahlen).

FWIW, SSDs sind nicht immer die beste Technologie für schreibintensive 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 vorgewachsen ist und das Protokoll niemals abgeschnitten wird.

3
RickNZ

Eine andere DMV, mit der ich Langsamkeit identifiziere, ist sys.dm_os_waiting_tasks . Wenn Ihre Abfrage nicht CPU-intensiv ist, finden Sie in dieser DMV weitere Informationen zu den Wartezeiten.

1
StanleyJohns

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, da ich einfach neugierig bin, wie/warum dieses Warteereignis für diese Version angezeigt wird.

Wenn überhaupt eine Netzwerkwartezeit angezeigt wird, kann dies auch dann passieren, 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: Speicher, 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.

0
SQLRockstar