Wie kann ich einer großen Tabelle eine Zeilenversionsspalte mit minimalen Ausfallzeiten hinzufügen?

21

Unter Verwendung von SQL Server 2008 und höher möchte ich einer großen Tabelle jedoch eine Zeilenversionsspalte hinzufügen, wenn ich es einfach mache

ALTER TABLE [Tablename]
ADD Rowversion [Rowversion] NOT NULL

In diesem Fall ist die Tabelle für zu lange Aktualisierungen nicht verfügbar.

Welche Strategien kann ich verwenden, um diese Ausfallzeiten zu reduzieren? Ich werde alles in Betracht ziehen. Je einfacher desto besser natürlich, aber ich werde jede Strategie in Betracht ziehen.

Meiner Meinung nach könnte ich als letzten Ausweg eine von Triggern verwaltete Kopie-Staging-Tabelle verwalten und die Staging-Tabelle dann mit sp_rename in die Originaltabelle umbenennen. Aber ich hoffe auf etwas Einfacheres / Leichteres.

Michael J Swart
quelle

Antworten:

26

Ziehen Sie in Betracht, eine neue Tabelle mit demselben Schema und der Zeilenversionsspalte zu erstellen, und fügen Sie auf beiden Tabellen eine Ansicht hinzu, die alle zusammenfasst. Lassen Sie die Ansicht von Personen verwenden und schreiben Sie anstelle von Triggern auf die zugrunde liegenden Tabellen und Ansichten.

Einfügungen sollten an die neue Tabelle gesendet werden, Aktualisierungen sollten Daten in die neue Tabelle verschieben und Löschungen sollten auf beide Tabellen angewendet werden.

Führen Sie dann Stapelverschiebungen im Hintergrund aus und verschieben Sie so viele Datensätze wie möglich gleichzeitig in die neue Tabelle. Währenddessen kann es immer noch zu Problemen mit der Parallelität und einigen spektakulären Ausführungsplänen kommen. Sie können jedoch online bleiben, während die Umzüge stattfinden.

Im Idealfall starten Sie den Prozess an einem Freitagnachmittag, um die Auswirkungen auf die Endbenutzer zu minimieren, und versuchen, dies vor Montagmorgen zu erledigen. Sobald es eingerichtet ist, können Sie die Ansicht so ändern, dass sie nur auf die neue Tabelle verweist, und die spektakulären Ausführungspläne werden nicht mehr angezeigt. Im Idealfall.

Um zu vermeiden, dass die Trigger ausgelöst werden, wenn die Daten in Stapeln migriert werden, überprüfen Sie die Anzahl der Zeilen in den gelöschten / eingefügten Tabellen im Trigger und überspringen Sie die Aktivitäten, wenn sie der Anzahl der Zeilen in Ihrem Stapel nahekommen.


Im Ziel beschloss Michael, die Ansicht zu überspringen (und nicht aus der Originaltabelle zu löschen), um stabilere Pläne zu erhalten. Der Kompromiss bestand im Wesentlichen aus zwei Kopien der Tabelle. Er verwandelte es in eine Reihe von Blog-Posts .

Brent Ozar
quelle
7

Wenn Sie Zeit haben, im Voraus zu planen, gibt es eine viel einfachere Lösung ... (normalerweise)

Die langen Sperren werden mit ziemlicher Sicherheit durch Seitenteile auf der Speicherebene verursacht. Also zwinge sie nach deinem eigenen Zeitplan.

  1. Fügen Sie eine NULL-fähige temporäre Spalte mit Datentyp hinzu VARBINARY(8).
  2. Suchen Sie die verfügbare Pufferzeit in der Datenbank, um Stapel der vorhandenen Datensätze mit einem gültigen Wert für das Feld zu aktualisieren. ( 0x0000000027F95A5Bzum Beispiel)
  3. Durch die Aktualisierungen werden die erforderlichen Seitenteile erzwungen und der Tabelle mehr Speicherplatz zugewiesen.
  4. Wenn Sie fertig sind, löschen Sie die temporäre Spalte (ohne den zugewiesenen Speicher zu berühren) und fügen Sie die Zeilenversionsspalte hinzu.
  5. Keine Seitenteilung und eine Sperre, die nur lang genug ist, um die Werte aufzufüllen.

Ich habe dies erfolgreich verwendet, um einer 150 Millionen Zeilentabelle in weniger als 10 Minuten eine Zeilenversionsspalte hinzuzufügen.

Vorsichtsmaßnahme ... wenn Sie eine Tabelle mit großen varchar-Feldern haben (insbesondere varchar(max)), beschließt SQL Server, die Tabelle neu zu erstellen , anstatt den neu verfügbaren Speicherplatz erneut zu verwenden. Ich versuche immer noch, einen Weg zu finden, um dieses Problem zu umgehen.

Scott Lynch
quelle
Interessanterweise habe ich in meiner Frage nicht angegeben, was "zu lang" bedeutet. Wenn> 30 Minuten für Ihr Szenario zu lang und 10 Minuten tolerierbar sind, funktioniert diese Lösung. Mein Szenario beinhaltete den Versuch, keine Ausfallzeit oder genauer gesagt <10 Sekunden zu erreichen, was durch Brents Antwort erreicht wird.
Michael J Swart
1

Wenn TIMESTAMPSie Folgendes hinzufügen NULLABLE:

  1. Fügen Sie eine VARBINARY(8)Spalte hinzu
  2. Füllen Sie mit Daten.

Nach dem Auffüllen DROPder VARBINARY(8)Spalte , die Sie gerade hinzugefügt und ausgefüllt haben, und Hinzufügen der TIMESTAMP NULLSpalte in Back-to-Back-SQL-Anweisungen .


Wenn TIMESTAMPSie Folgendes hinzufügen NOT NULLABLE:

  1. Fügen Sie eine BINARY(8)Spalte hinzu
  2. Füllen Sie mit Daten.

Nach dem Auffüllen DROPder BINARY(8)Spalte , die Sie gerade hinzugefügt haben, und der Spalte , die Sie aufgefüllt haben, in den SQL-Anweisungen "back to back" ADD THE TIMESTAMP NOT NULL.

Paul White sagt GoFundMonica
quelle