Was ist der beste Weg, um alle bis auf das aktuelle Jahr zu archivieren und die Tabelle gleichzeitig zu partitionieren

23

Aufgabe

Archivieren Sie alle bis auf einen fortlaufenden Zeitraum von 13 Monaten aus einer Gruppe großer Tische. Die archivierten Daten müssen in einer anderen Datenbank gespeichert werden.

  • Die Datenbank befindet sich im einfachen Wiederherstellungsmodus
  • Die Tabellen haben eine Größe von 50 Millionen Zeilen bis zu mehreren Milliarden Zeilen und nehmen in einigen Fällen jeweils Hunderte von GB ein.
  • Die Tabellen sind derzeit nicht partitioniert
  • Jede Tabelle verfügt über einen Clustered-Index für eine immer größer werdende Datumsspalte
  • Jede Tabelle hat zusätzlich einen nicht gruppierten Index
  • Alle Datenänderungen an den Tabellen sind Einfügungen
  • Ziel ist es, Ausfallzeiten der Primärdatenbank zu minimieren.
  • Server ist 2008 R2 Enterprise

Die Tabelle "archive" wird ungefähr 1,1 Milliarden Zeilen haben, die Tabelle "live" ungefähr 400 Millionen. Natürlich wird die Archivtabelle mit der Zeit größer, aber ich gehe davon aus, dass auch die Live-Tabelle einigermaßen schnell größer wird. Sagen wir mindestens 50% in den nächsten paar Jahren.

Ich hatte über Azure-Stretch-Datenbanken nachgedacht, aber leider befinden wir uns in Version 2008 R2 und werden wahrscheinlich noch eine Weile dort bleiben.

Derzeitiger Plan

  • Erstellen Sie eine neue Datenbank
  • Erstellen Sie neue Tabellen, die nach Monat (unter Verwendung des Änderungsdatums) in der neuen Datenbank partitioniert sind.
  • Verschieben Sie die Daten der letzten 12 bis 13 Monate in die partitionierten Tabellen.
  • Führen Sie einen Umbenennungsaustausch der beiden Datenbanken durch
  • Löschen Sie die verschobenen Daten aus der jetzt "archivierten" Datenbank.
  • Partitionieren Sie jede der Tabellen in der Datenbank "archive".
  • Verwenden Sie Partition Swaps, um die Daten in Zukunft zu archivieren.
    • Mir ist klar, dass ich die zu archivierenden Daten auslagern, diese Tabelle in die Archivdatenbank kopieren und dann in die Archivtabelle umlagern muss. Das ist akzeptabel.

Problem: Ich versuche, die Daten in die anfänglich partitionierten Tabellen zu verschieben (tatsächlich führe ich immer noch einen Proof-of-Concept-Test durch). Ich versuche, TF 610 (gemäß dem Data Loading Performance Guide ) und eine INSERT...SELECTAnweisung zu verwenden, um die Daten zu verschieben, die anfänglich für minimal protokolliert gehalten werden. Leider ist es jedes Mal, wenn ich es versuche, vollständig protokolliert.

An diesem Punkt denke ich, dass meine beste Wette darin besteht, die Daten mit einem SSIS-Paket zu verschieben. Ich versuche das zu vermeiden, da ich mit 200 Tabellen arbeite und alles, was ich per Skript tun kann, einfach generieren und ausführen kann.

Fehlt in meinem allgemeinen Plan etwas, und ist SSIS meine beste Wahl, um die Daten schnell und mit minimaler Verwendung des Protokolls zu verschieben (Platzprobleme)?

Demo Code ohne Daten

-- Existing structure
USE [Audit]
GO

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
); 
-- ~1.4 bill rows, ~20% in the last year

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(   [Modified] ASC   )
GO


-- New DB & Code
USE Audit_New
GO

CREATE PARTITION FUNCTION ThirteenMonthPartFunction (datetime)
AS RANGE RIGHT FOR VALUES ('20150701', '20150801', '20150901', '20151001', '20151101', '20151201', 
                            '20160101', '20160201', '20160301', '20160401', '20160501', '20160601', 
                            '20160701') 

CREATE PARTITION SCHEME ThirteenMonthPartScheme AS PARTITION ThirteenMonthPartFunction
ALL TO ( [PRIMARY] );

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
) ON ThirteenMonthPartScheme (Modified)
GO

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

CREATE NONCLUSTERED INDEX [AuditTable_Col1_Col2_Col3_Col4_Modified] ON [dbo].[AuditTable]
(
    [Col1] ASC,
    [Col2] ASC,
    [Col3] ASC,
    [Col4] ASC,
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

Code verschieben

USE Audit_New
GO
DBCC TRACEON(610);

INSERT INTO AuditTable
SELECT * FROM Audit.dbo.AuditTable
WHERE Modified >= '6/1/2015'
ORDER BY Modified
Kenneth Fisher
quelle
RE "Verschieben der Daten": Um die Protokollnutzung zu minimieren, können Sie Daten stapelweise verschieben, z. B. "Approch 2" in dba.stackexchange.com/a/139009/94130 . Haben Sie beim Thema Partitionierung partitionierte Ansichten in Betracht gezogen?
Alex
@ Alex Ja, ich habe beide in Betracht gezogen. Mein Sicherungsplan besteht darin, die Daten mithilfe von SSIS stapelweise zu verschieben. Und für diesen speziellen Fall ist mein Problem genau das, wofür Partitionierung erstellt wurde. (schnelles Laden / Entladen von Daten mittels Switching)
Kenneth Fisher

Antworten:

10

Warum erhalten Sie keine minimale Protokollierung?

Ich habe das gefunden , dass das von Ihnen erwähnte Data Loading Performance Guide eine äußerst wertvolle Ressource ist. Es ist jedoch auch nicht zu 100% umfassend, und ich vermute, dass das Raster bereits so komplex ist, dass der Autor keine Spalte hinzugefügt hat Table Partitioning, um Unterschiede im Verhalten herauszustellen, je nachdem, ob die Tabelle, die die Einfügungen empfängt, partitioniert ist. Wie wir später sehen werden, scheint die Tatsache, dass die Tabelle bereits partitioniert ist, eine minimale Protokollierung zu verhindern.

Bildbeschreibung hier eingeben

Empfohlener Ansatz

Basierend auf den Empfehlungen im Datenlade-Leistungshandbuch (einschließlich des Abschnitts "Massenladen einer partitionierten Tabelle") sowie umfangreichen Erfahrungen beim Laden partitionierter Tabellen mit mehreren zehn Milliarden Zeilen, würde ich diesen Ansatz empfehlen:

  • Erstellen Sie eine neue Datenbank.
  • Erstellen Sie neue Tabellen, die nach Monat in der neuen Datenbank partitioniert sind.
  • Verschieben Sie das letzte Jahr der Daten auf folgende Weise:
    • Erstellen Sie für jeden Monat eine neue Heap-Tabelle.
    • Fügen Sie den Monat der Daten mit dem TABLOCK-Hinweis in den Heap ein.
    • Fügen Sie den Clustered-Index dem Heap hinzu, der den Monat der Daten enthält.
    • Fügen Sie die Prüfbedingung hinzu, die erzwingt, dass die Tabelle nur die Daten dieses Monats enthält.
    • Wechseln Sie die Tabelle in die entsprechende Partition der neuen insgesamt partitionierten Tabelle.
  • Führen Sie einen Umbenennungsaustausch der beiden Datenbanken durch.
  • Kürzen Sie die Daten in der Datenbank now "archive".
  • Partitionieren Sie jede der Tabellen in der Datenbank "archive".
  • Verwenden Sie Partition Swaps, um die Daten in Zukunft zu archivieren.

Die Unterschiede im Vergleich zu Ihrem ursprünglichen Ansatz:

  • Die Methode zum Verschieben der Daten der letzten 12 bis 13 Monate ist wesentlich effizienter, wenn Sie TABLOCKdie Daten mit Hilfe der Partitionsumschaltung nach jeweils einem Monat in einen Heap laden , um sie in die partitionierte Tabelle zu verschieben.
  • Ein DELETEzu räumender alter Tisch wird vollständig protokolliert. Vielleicht können Sie entweder TRUNCATEdie Tabelle löschen oder eine neue Archivtabelle erstellen.

Vergleich der Ansätze zum Verschieben der Daten aus dem letzten Jahr

Um die Ansätze auf meinem Computer in angemessener Zeit zu vergleichen, habe ich einen 100MM rowTestdatensatz verwendet, den ich generiert habe und der Ihrem Schema folgt.

Wie Sie aus den folgenden Ergebnissen ersehen können, werden die Protokollschreibvorgänge erheblich beschleunigt und verringert, indem Daten mithilfe des TABLOCKHinweises in einen Heap geladen werden. Es gibt einen zusätzlichen Vorteil, wenn dies jeweils für eine Partition durchgeführt wird. Beachten Sie auch, dass die Methode "Eine Partition gleichzeitig" problemlos weiter parallelisiert werden kann, wenn Sie mehrere Partitionen gleichzeitig ausführen. Abhängig von Ihrer Hardware kann dies zu einem positiven Effekt führen. Normalerweise laden wir mindestens vier Partitionen gleichzeitig auf Hardware der Serverklasse.

Bildbeschreibung hier eingeben

Hier ist das vollständige Testskript .

Schlussnoten

Alle diese Ergebnisse hängen zu einem gewissen Grad von Ihrer Hardware ab. Meine Tests wurden jedoch auf einem Standard-Quad-Core-Laptop mit drehendem Festplattenlaufwerk durchgeführt. Es ist wahrscheinlich, dass das Laden der Daten viel schneller sein sollte, wenn Sie einen anständigen Server verwenden, der zum Zeitpunkt der Durchführung dieses Vorgangs nicht viele andere Lasten aufweist.

Zum Beispiel habe ich den empfohlenen Ansatz auf einem tatsächlichen Entwickler-Server (Dell R720) ausgeführt und eine Reduzierung auf 76 seconds(von 156 secondsmeinem Laptop) festgestellt . Interessanterweise hat der ursprüngliche Ansatz des Einfügens in eine partitionierte Tabelle nicht die gleiche Verbesserung erfahren und wurde immer noch nur 12 minutesauf dem Entwickler-Server übernommen. Vermutlich liegt dies daran, dass dieses Muster einen seriellen Ausführungsplan ergibt und ein einzelner Prozessor auf meinem Laptop mit einem einzelnen Prozessor auf dem Entwicklungsserver übereinstimmen kann.

Geoff Patterson
quelle
Nochmals vielen Dank, Geoff. Ich benutze die SWITCH-Methode. Insbesondere verwende ich SSIS und dynamisches SQL, um die 13 Monate parallel auszuführen.
Kenneth Fisher
1

Dies könnte ein guter Kandidat für Biml sein. Ein Ansatz wäre, eine wiederverwendbare Vorlage zu erstellen, mit der Daten für eine einzelne Tabelle in kleinen Datumsbereichen mit einem For Each-Container migriert werden. Das Biml durchläuft Ihre Tabellensammlung, um identische Pakete für jede qualifizierende Tabelle zu erstellen. Andy Leonard hat ein Intro in seiner Stairway-Serie .

MattyZDBA
quelle
0

Anstatt die neue Datenbank zu erstellen, können Sie die reale Datenbank auch in einer neuen Datenbank wiederherstellen und die neuesten Daten für 12 bis 13 Monate löschen. Dann löschen Sie in Ihrer realen Datenbank die Daten, die nicht in Ihrem gerade erstellten Archivbereich enthalten sind. Wenn große Löschvorgänge ein Problem darstellen, können Sie möglicherweise einfach 10 KB oder größere Sätze per Skript löschen, um dies zu tun.

Ihre Partitionierungsaufgaben scheinen nicht beeinträchtigt zu sein und nach dem Löschen auf beide Datenbanken anwendbar zu sein.

John
quelle
Ich habe das schon mit kleineren Datenbanken gemacht. Angesichts der aktuellen Größe und der Tatsache, dass ich auf beiden Seiten partitionierte Tabellen haben möchte, würde diese Methode meines Erachtens tatsächlich länger und einiges mehr Speicherplatz in Anspruch nehmen (doppelte aktuelle DB-Größe bei Minute)
Kenneth Fisher