Wie kann Transaktionsprotokoll Wachstum für batched nvarchar (max) Updates reduzieren
-
19-09-2019 - |
Frage
Unsere App benötigen große Mengen an Text zu SQL Server 2005-Datenbank hinzuzufügen (bis zu 1 GB für einen einzelnen Datensatz). Aus Performance-Gründen ist dies in Blöcken erfolgt durch Aufruf einer gespeicherten Prozedur für jeden Chunk machen (sagen wir, usp_AddChunk). usp_AddChunk keine expliziten Transaktionen hat.
Was ich sehe, ist, dass in massiv größeren Transaktionsprotokollen die Blockgröße von 100 MB bis 10 MB Ergebnisse zu reduzieren. Ich habe gesagt, dies liegt daran, dass jedes Mal, usp_AddChunk genannt wird, eine „implizite“ (mein Ausdruck) Transaktion wird alle bestehenden Text protokolliert. Also, für einen 150 MB Rekord:
100MB Chunkgröße: 100 (0 Bytes angemeldet) + 50 (100 MB angemeldet) = 100 MB angemeldet
wird kleiner sein als
10 MB Chunkgröße: 10 (0 Bytes angemeldet) + 10 (10 MB angemeldet) + 10 (20 MB angemeldet) ... + 10 (140 MB angemeldet) = 1050 MB protokollierten
Ich dachte, dass durch eine Transaktion in meinem C # -Code zu öffnen, diese „implizite“ Transaktion nicht passieren würde (bevor ich die ersten Brocken, und begehen nach dem letzten Brocken hinzufügen), und ich konnte die riesigen Log-Dateien vermeiden. Aber meine Tests zeigen, das Transaktionsprotokoll 5x immer größer die ADO.NET-Transaktion.
Ich werde den Code nicht veröffentlichen, aber hier ein paar Details:
- Ich nenne SqlConnection.BeginTransaction ()
- Ich verwende eine andere SqlCommand für jeden Chunk
- I ordnen die SqlTransaction von (1) zu jedem SqlCommand
- I in der Regel die Verbindung nach jeder SqlCommand Ausführung schließen, aber ich habe auch versucht, die Verbindung mit den gleichen Ergebnissen nicht schließen
Was ist der Fehler in diesem System? Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen. Dank!
Hinweis: ein einfaches oder Bulk-Protokollierung unter Verwendung von Wiederherstellungsmodell ist keine Option
Lösung
Wenn von 'Brocken' meinen Sie so etwas wie:
UPDATE table
SET blob = blob + @chunk
WHERE key = @key;
Dann sind Sie richtig, dass der Betrieb vollständig protokolliert. Sie sollten die BLOB Nutzungsrichtlinien und Nutzung folgen die .Write Methoden für chuncked Updates:
UPDATE table
SET blob.Write(@chunk, NULL, NULL)
WHERE key = @key;
Dies wird minimal das Update log (wenn möglich, siehe Operationen das sein kann minimal protokollierte ):
Die UPDATE-Anweisung wird vollständig protokolliert; jedoch teilweise Updates zu groß Wert-Datentypen der .WRITE mit Klausel ist minimal protokolliert.
Nicht nur, dass diese minimal protokolliert wird, sondern weil das Update am Ende des BLOB eine explizite Schreib ist, wird der Motor, dass Sie nur einen Teil des BLOB aktualisiert und wird nur log , die . Wenn Sie mit SET blob=blob+@chunk
te Motor aktualisiert werden sehen, dass die gesamte BLOB einen neuen Wert erhalten hat und wird die Tatsache nicht erkennen, dass Sie wirklich nur die BLOB geändert durch neue Daten angehängt, so dass die sie das gesamte BLOB (mehrmals einzuloggen, wie Sie bereits herausgefunden).
BTW sollten Sie Brocken Größe Vielfaches von 8040 verwenden:
Für eine optimale Leistung empfehlen wir, daß Daten eingefügt oder aktualisiert werden, in Blockgrößen, die ein Vielfaches von 8040 sind Bytes.
Andere Tipps
Was können Sie tun müssen, ist jedes „Brocken“ umgeben oder eine Gruppe von Stücken mit einer eigenen Transaktion und nach jeder Gruppe begehen. Rund um die ganze Sache mit Ihrem eigenen ADO-Transaktion wird die gleiche Sache im Wesentlichen tun, wie die implizite Transaktion der Fall ist, so dass nicht helfen. Sie haben in kleinere Stücke zu begehen das Protokoll kleiner zu halten.