Verbessern Sie die Geschwindigkeit der Indexwiederherstellung auf SQL Server

9

Ich importiere eine große Datenmenge in eine leere Datenbank und habe vor dem Start alle nicht eindeutigen nicht gruppierten Indizes deaktiviert, um festzustellen, ob ich die Leistung des Imports verbessern kann.

Jetzt möchte ich die Indizes wieder aktivieren und frage mich, ob ich etwas tun kann, um dies zu optimieren.

Es müssen> 100 Tabellen und fast 2.000 Indizes neu erstellt werden. Die Datenbank ist 200 GB groß.

Der Schlüsselabschnitt des Skripts, das ich ausführe, ist folgender:

declare c_toggle_index cursor FORWARD_ONLY READ_ONLY for
    select  'alter index ' + QUOTENAME(i.name) + ' on ' + o.name + ' rebuild'
    from    sys.indexes as i
    Inner Join sys.objects o
    On o.object_id = i.object_id
    Where o.is_ms_shipped = 0
    And i.index_id >= 1
    and i.type > 1
    and i.is_disabled = 1

Ich habe überlegt, ONLINE = OFF für die Anweisung alter index zu setzen, aber als die Indizes deaktiviert beginnen, war ich mir nicht sicher, ob diese Einstellung Auswirkungen haben würde. Ich habe auch überlegt, SORT_IN_TEMPDB = ON zu setzen, aber da sich die Tempdb-Dateien auf demselben Laufwerk befinden wie die MDF-Dateien der Datenbanken, habe ich angenommen, dass dies auch keinen Vorteil hat.

Beim Ausführen des Wiederherstellungsskripts habe ich festgestellt, dass ich viele CXPACKET-Wartetypen habe. Ich verstehe nicht wirklich, warum das so ist oder ob es ein Problem ist, das ich ansprechen sollte.

Ein letzter Punkt, der relevant sein kann: Mein gesamter Server ist derzeit inaktiv, abgesehen von diesem Import von Daten in die Datenbank. Es gibt keine andere Benutzeraktivität, die berücksichtigt oder befürchtet werden muss. Mein einziges Anliegen ist es, die Daten in kürzester Zeit in die Datenbank zu importieren.

paulH
quelle
3
Wenn Sie sagen, dass Ihre einzige Sorge die Importzeit ist, meinen Sie die Zeit vom Beginn des Imports bis zum Ende der erneuten Aktivierung der Indizes? In diesem Fall sollten Sie die Indizes nur während des Imports aktiviert lassen. 2.000 Indizes für 200 GB Daten klingen für mich nach vielen Indizes. Vielleicht sollten Sie sich die DMVs für die Indexverwendung ansehen, um festzustellen, ob einige entfernt werden könnten.
Max Vernon
1
Um dies zu verdeutlichen, müssen Sie denselben 200-GB-Import wiederholt und nicht nur einmal durchführen.
Jon Seigel
1
Ich muss den Import nur einmal durchführen, aber als Teil eines größeren Prozesses mit einem begrenzten Zeitfenster. Daher teste ich diesen Prozess derzeit, damit er in dieses Fenster passt. @MaxVernon Es sieht so aus, als ob Sie Recht haben, dass das Aktivieren der Indizes der schnellste Weg ist, obwohl ich überrascht bin, als ich gelesen habe, dass es normalerweise schneller war, die Indizes zu deaktivieren, die Daten zu importieren und die Indizes wieder zu aktivieren. Dies ist eine Datenbank von Drittanbietern, sodass das Entfernen oder anderweitige Ändern von Indizes nicht wirklich möglich ist.
PaulH
3
In Ordnung. Informationen zu den CXPACKETWartezeiten: Der Index erstellt sich selbst neu. Scan-Indizes (sogar der Index, der neu erstellt wird ), und diese Scans können Parallelität verwenden. Sie sollten sich keine Sorgen um diese Wartezeiten machen - die Parallelität hilft wahrscheinlich.
Jon Seigel

Antworten:

10

Um in diesem Szenario eine optimale Importleistung zu erzielen, sind drei Dinge erforderlich:

  1. Minimal protokollierte Basistabelleneinsätze
  2. Minimal protokollierte nicht gruppierte Indexerstellungen
  3. Vermeiden physischer Lesevorgänge

Minimale Protokollierung

Um minimal protokollierte Einfügungen in eine leere Clustertabelle ohne nicht gruppierte Indizes zu erzielen, sind folgende Voraussetzungen erforderlich:

  1. Verwenden Sie entweder das SIMPLEoder das BULK_LOGGEDDatenbankwiederherstellungsmodell
  2. Angeben einer Tabellensperre und einer geordneten Eingabe (z. B. TABLOCKund ORDERHinweise)

Randnotiz:

Es ist auch möglich, minimal protokollierte Einfügungen in eine gruppierte Tabelle zu erzielen, die nicht gruppierte Indizes aufweist, vorausgesetzt, das Ablaufverfolgungsflag 610 ist aktiviert. Ob nicht gruppierte Indexeinfügungen minimal protokolliert werden oder nicht, hängt vom vom Abfrageoptimierer ausgewählten Abfrageplan ab.

Wenn der Abfrageplan einen separaten Iterator für den nicht gruppierten Index verwendet und für den Iterator die DMLRequestSortEigenschaft festgelegt ist true, werden die nicht gruppierten Indexeinfügungen minimal protokolliert, sofern die anderen zuvor genannten Bedingungen erfüllt sind.

Nicht gruppierte Indizes separat erstellen

Dies hat folgende Vorteile:

  1. Clustered Index Inserts können minimal protokolliert werden, ohne TF 610 zu aktivieren
  2. CREATE INDEX wird minimal protokolliert, wenn das Wiederherstellungsmodell nicht vorhanden ist FULL

Vermeiden physischer Lesevorgänge

Im Idealfall werden die zu importierenden Daten auf einem separaten Computer oder zumindest auf einem anderen physischen Speicher als dem zum Hosten der Datenbank verwendeten gespeichert.

Der Datenbankserver sollte über genügend Speicher verfügen, um die größte Basistabelle im Cache zu speichern, und über genügend Speicherplatz für Sortiervorgänge verfügen, die beim Erstellen von nicht gruppierten Indizes erforderlich sind.

Ein gutes Muster besteht darin, die Basistabelle schnell zu laden (minimal protokollierte Clustered-Index-Last) und dann alle nicht-Clustered-Indizes für diese Tabelle zu erstellen, während ihre Datenseiten noch zwischengespeichert sind.

Die Frage beschreibt einen Prozess, bei dem zuerst Basistabellen geladen und dann nicht gruppierte Indizes erstellt werden. Die Cursordefinition verwendet keine ORDER BYKlausel , um nicht gruppierte Indexbuilds, die auf derselben Tabelle basieren, zumindest zu gruppieren.

Das wahrscheinliche Ergebnis ist, dass Datenseiten für verschiedene Tabellen wiederholt in den Cache eingelesen und dann verworfen werden, wenn nicht gruppierte Indizes in einer nicht deterministischen Reihenfolge erstellt werden.

Die Kosten für wiederholte physische Lesevorgänge dominieren vollständig die Vorteile einer minimalen Protokollierung, die durch die separate Erstellung nicht gruppierter Indizes erzielt wird. Dies erklärt, warum Sie festgestellt haben, dass das Laden von Tabellen mit vorhandenen Indizes schneller ist (da alle nicht gruppierten Indizes für eine bestimmte Tabelle beibehalten werden, bevor Sie mit der nächsten Tabelle fortfahren).

Zusammenfassung

Der Importvorgang sollte überarbeitet werden, um jeweils eine Tabelle in großen Mengen zu laden. Dies bedeutet, dass Sie die Tabelle laden und alle nicht gruppierten Indizes erstellen, bevor Sie mit dem nächsten fortfahren. Die SQL Server-Instanz sollte über genügend Speicher verfügen, um die größte Tabelle aufzunehmen und gleichzeitig die größte nicht gruppierte Indexsortierung durchzuführen.

Sie können auch versuchen, TF 610 zu aktivieren, bevor Sie die Daten in Tabellen mit bereits vorhandenen Cluster-Indizes laden. Dies ist normalerweise nicht so schnell wie die vorherige Methode, kann aber schnell genug sein.

Weitere Informationen finden Sie im Folgenden:

Das Handbuch zum Laden von Daten

Vorgänge, die minimal protokolliert werden können

Paul White 9
quelle