Ich muss mit dem BULK INSERT
Befehl von SQL Server einen ziemlich alten Code neu schreiben, da sich das Schema geändert hat, und mir ist der Gedanke gekommen, dass ich vielleicht stattdessen über einen Wechsel zu einer gespeicherten Prozedur mit einem TVP nachdenken sollte, aber ich frage mich, welchen Effekt dies hat es könnte auf Leistung haben.
Einige Hintergrundinformationen, die erklären könnten, warum ich diese Frage stelle:
Die Daten kommen tatsächlich über einen Webdienst ein. Der Webdienst schreibt eine Textdatei in einen freigegebenen Ordner auf dem Datenbankserver, der wiederum eine ausführt
BULK INSERT
. Dieser Prozess wurde ursprünglich auf SQL Server 2000 implementiert, und zu der Zeit gab es wirklich keine andere Alternative, als ein paar hundertINSERT
Anweisungen auf dem Server abzulegen, was eigentlich der ursprüngliche Prozess war und eine Leistungskatastrophe darstellte.Die Daten werden in großen Mengen in eine permanente Staging-Tabelle eingefügt und dann in eine viel größere Tabelle zusammengeführt (wonach sie aus der Staging-Tabelle gelöscht werden).
Die einzufügende Datenmenge ist "groß", aber nicht "riesig" - normalerweise einige hundert Zeilen, in seltenen Fällen vielleicht 5-10.000 Zeilen oben. Daher mein Bauchgefühl ist , dass
BULK INSERT
eine nicht protokollierte Operation ist nicht machen , dass die großen Unterschied (aber natürlich bin ich nicht sicher, daher die Frage).Das Einfügen ist tatsächlich Teil eines viel größeren Pipeline-Batch-Prozesses und muss viele Male hintereinander erfolgen. daher Leistung ist entscheidend.
Die Gründe, warum ich das BULK INSERT
durch ein TVP ersetzen möchte, sind:
Das Schreiben der Textdatei über NetBIOS kostet wahrscheinlich bereits einige Zeit und ist aus architektonischer Sicht ziemlich grausam.
Ich glaube, dass die Staging-Tabelle beseitigt werden kann (und sollte). Der Hauptgrund dafür ist, dass die eingefügten Daten gleichzeitig mit dem Einfügen für einige andere Aktualisierungen verwendet werden müssen und es weitaus teurer ist, die Aktualisierung aus der massiven Produktionstabelle zu versuchen, als eine fast leere Bereitstellung Tabelle. Mit einem TVP, der Parameter im Grunde ist die Zwischenspeichertabelle, ich alles tun , kann ich damit vor wollen / nach dem Haupteinsatz.
Ich könnte die Dupe-Überprüfung, den Bereinigungscode und den gesamten mit Masseneinfügungen verbundenen Overhead so gut wie beseitigen.
Sie müssen sich keine Gedanken über Sperrenkonflikte in der Staging-Tabelle oder in der Tempdb machen, wenn der Server einige dieser Transaktionen gleichzeitig erhält (wir versuchen, dies zu vermeiden, aber es passiert).
Ich werde dies natürlich profilieren, bevor ich etwas in Produktion bringe, aber ich dachte, es wäre eine gute Idee, zuerst nachzufragen, bevor ich die ganze Zeit damit verbringe, zu prüfen, ob jemand strenge Warnungen bezüglich der Verwendung von TVPs für diesen Zweck hat.
Also - für alle, die mit SQL Server 2008 vertraut genug sind, um dies zu versuchen oder zumindest zu untersuchen, wie lautet das Urteil? Schneiden Beilagen für Einsätze von beispielsweise einigen hundert bis einigen tausend Zeilen, die ziemlich häufig vorkommen, den Senf? Gibt es einen signifikanten Leistungsunterschied zu Bulk-Einsätzen?
Update: Jetzt mit 92% weniger Fragezeichen!
(AKA: Testergebnisse)
Das Endergebnis ist jetzt nach einem 36-stufigen Bereitstellungsprozess in der Produktion. Beide Lösungen wurden ausgiebig getestet:
- Herausreißen des Codes für freigegebene Ordner und
SqlBulkCopy
direkte Verwendung der Klasse; - Wechseln zu einer gespeicherten Prozedur mit TVPs.
Damit die Leser eine Vorstellung davon bekommen, was genau getestet wurde, um Zweifel an der Zuverlässigkeit dieser Daten auszuräumen, finden Sie hier eine detailliertere Erläuterung der tatsächlichen Funktionsweise dieses Importvorgangs :
Beginnen Sie mit einer zeitlichen Datensequenz, die normalerweise etwa 20-50 Datenpunkte umfasst (obwohl sie manchmal einige hundert betragen kann).
Führen Sie eine ganze Reihe verrückter Verarbeitungen durch, die größtenteils unabhängig von der Datenbank sind. Dieser Prozess ist parallelisiert, so dass ungefähr 8-10 der Sequenzen in (1) gleichzeitig verarbeitet werden. Jeder parallele Prozess erzeugt 3 zusätzliche Sequenzen.
Nehmen Sie alle 3 Sequenzen und die Originalsequenz und kombinieren Sie sie zu einem Stapel.
Kombinieren Sie die Stapel aus allen 8-10 jetzt abgeschlossenen Verarbeitungsaufgaben zu einem großen Super-Stapel.
Importieren Sie es entweder mit der
BULK INSERT
Strategie (siehe nächster Schritt) oder mit der TVP-Strategie (fahren Sie mit Schritt 8 fort).Verwenden Sie die
SqlBulkCopy
Klasse, um den gesamten Super-Batch in 4 permanente Staging-Tabellen zu speichern.Führen Sie eine gespeicherte Prozedur aus, die (a) eine Reihe von Aggregationsschritten für 2 der Tabellen einschließlich mehrerer
JOIN
Bedingungen ausführt und (b) eineMERGE
für 6 Produktionstabellen unter Verwendung der aggregierten und nicht aggregierten Daten ausführt . (Fertig)ODER
Generieren Sie 4
DataTable
Objekte mit den zusammenzuführenden Daten. 3 von ihnen enthalten CLR-Typen, die von ADO.NET-TVPs leider nicht ordnungsgemäß unterstützt werden. Daher müssen sie als Zeichenfolgendarstellungen eingefügt werden, was die Leistung etwas beeinträchtigt.Führen Sie die TVPs einer gespeicherten Prozedur zu, die im Wesentlichen dieselbe Verarbeitung wie (7) ausführt, jedoch direkt mit den empfangenen Tabellen. (Fertig)
Die Ergebnisse waren ziemlich nahe beieinander, aber der TVP-Ansatz schnitt letztendlich im Durchschnitt besser ab, selbst wenn die Daten 1000 Zeilen um einen kleinen Betrag überstiegen.
Beachten Sie, dass dieser Importvorgang viele tausend Mal hintereinander ausgeführt wird. Daher war es sehr einfach, eine durchschnittliche Zeit zu ermitteln, indem einfach gezählt wurde, wie viele Stunden (ja, Stunden) erforderlich waren, um alle Zusammenführungen abzuschließen.
Ursprünglich dauerte eine durchschnittliche Zusammenführung fast genau 8 Sekunden (unter normaler Last). Durch Entfernen des NetBIOS-Kludges und Umschalten SqlBulkCopy
auf wurde die Zeit auf fast genau 7 Sekunden reduziert. Durch die Umstellung auf TVPs wurde die Zeit auf 5,2 Sekunden pro Charge weiter reduziert . Das ist eine 35% ige Verbesserung des Durchsatzes für einen Prozess, dessen Laufzeit in Stunden gemessen wird - also überhaupt nicht schlecht. Es ist auch eine Verbesserung von ~ 25% gegenüber SqlBulkCopy
.
Ich bin eigentlich ziemlich zuversichtlich, dass die wahre Verbesserung deutlich mehr war. Während des Tests stellte sich heraus, dass die endgültige Zusammenführung nicht mehr der kritische Pfad war. Stattdessen begann der Webdienst, der die gesamte Datenverarbeitung durchführte, unter der Anzahl der eingehenden Anforderungen zu knicken. Weder die CPU noch die Datenbank-E / A waren wirklich voll und es gab keine signifikante Sperraktivität. In einigen Fällen wurde zwischen aufeinanderfolgenden Zusammenführungen eine Lücke von einigen Sekunden im Leerlauf angezeigt. Es gab eine leichte Lücke, die jedoch bei der Verwendung viel kleiner war (etwa eine halbe Sekunde) SqlBulkCopy
. Aber ich nehme an, das wird eine Geschichte für einen anderen Tag.
Schlussfolgerung: Tabellenwertige Parameter sind BULK INSERT
bei komplexen Import- und Transformationsprozessen, die mit mittelgroßen Datensätzen ausgeführt werden, tatsächlich besser als Operationen.
Ich möchte noch einen weiteren Punkt hinzufügen, um die Besorgnis einiger Leute zu lindern, die Pro-Staging-Tische sind. In gewisser Weise ist dieser gesamte Service ein riesiger Staging-Prozess. Jeder Schritt des Prozesses wird stark geprüft, sodass wir keine Staging-Tabelle benötigen, um festzustellen, warum eine bestimmte Zusammenführung fehlgeschlagen ist (obwohl dies in der Praxis fast nie der Fall ist). Alles was wir tun müssen, ist ein Debug-Flag im Service zu setzen und es wird zum Debugger brechen oder seine Daten in eine Datei anstelle der Datenbank sichern.
Mit anderen Worten, wir haben bereits mehr als genug Einblick in den Prozess und benötigen nicht die Sicherheit eines Staging-Tisches. der einzige Grund , warum ich war die Staging - Tabelle in erster Linie hatte Dreschen auf alle die zu vermeiden INSERT
und UPDATE
Aussagen , die wir sonst verwenden gehabt hätten. Im ursprünglichen Prozess lebten die Staging-Daten ohnehin nur für Bruchteile einer Sekunde in der Staging-Tabelle, sodass sie in Bezug auf Wartung / Wartbarkeit keinen Mehrwert erbrachten.
Beachten Sie auch, dass wir nicht jede einzelne BULK INSERT
Operation durch TVPs ersetzt haben. Einige Vorgänge, die sich mit größeren Datenmengen befassen und / oder mit den Daten nichts Besonderes tun müssen, als sie in die Datenbank zu werfen, werden weiterhin verwendet SqlBulkCopy
. Ich behaupte nicht, dass TVPs ein Allheilmittel für die Leistung sind, sondern nur, dass sie SqlBulkCopy
in diesem speziellen Fall erfolgreich waren und mehrere Transformationen zwischen der anfänglichen Inszenierung und der endgültigen Zusammenführung beinhalteten.
Da haben Sie es also. Punkt geht an TToni, um den relevantesten Link zu finden, aber ich schätze auch die anderen Antworten. Danke noch einmal!