So erstellen Sie einen Clustered-Index für eine 100-GB-Tabelle

8

Ich habe eine Heap-Tabelle, die ungefähr 104 GB Speicherplatz mit fast 3 Milliarden Zeilen benötigt. Ich versuche, einen Clustered-Index für diese Tabelle in der WeekEndingDateSpalte [ ] zu erstellen . Ich habe ungefähr 200 GB frei in der Datendatei und ungefähr 280 GB frei in der Tempdb.

Ich habe zwei verschiedene Methoden ausprobiert. Zunächst wurde der Index mit dem folgenden Befehl direkt in der Tabelle erstellt:

CREATE CLUSTERED INDEX CX_WT_FOLD_HISTORY
ON WT_FOLD_HISTORY (WeekEndingDate ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON, 
IGNORE_DUP_KEY = OFF
, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, 
DATA_COMPRESSION = PAGE)

Ich habe es sowohl mit SORT_IN_TEMPDB = ONals auch versucht OFF. Bei Verwendung ONfüllte es die Tempdb und damit das Datenlaufwerk OFF.

Eine andere Methode bestand darin, eine neue leere Tabelle mit dem erforderlichen Index zu erstellen und dann die Datensätze aus dem Heap in die neue Tabelle einzufügen. Dies schlug auch nach dem Auffüllen des Datenlaufwerks fehl.

Weitere Vorschläge, was zu tun ist. Die meisten Dinge, die ich gelesen habe, besagten, dass ich ungefähr das 1,2-fache der Größe der Tabelle benötigen würde, um beim Erstellen des Index als Arbeitsbereich verwendet zu werden. Ich habe weit mehr als das und es scheitert immer noch. Anregungen wäre dankbar.

Hier ist meine ursprüngliche Heap-Tabellenstruktur:

CREATE TABLE [dbo].[WT_FOLD_HISTORY](
[WeekEndingDate] [varchar](50) NULL,
[Division] [varchar](50) NULL,
[Store] [varchar](50) NULL,
[SKUNumber] [varchar](50) NULL,
[UPC] [varchar](50) NULL,
[SalesUnits] [varchar](50) NULL,
[SalesCost] [varchar](50) NULL,
[SalesRetail] [varchar](50) NULL,
[InventoryUnits] [varchar](50) NULL,
[InventoryCost] [varchar](50) NULL,
[InventoryRetail] [varchar](50) NULL,
[OnOrderUnits] [varchar](50) NULL,
[OnOrderCost] [varchar](50) NULL,
[OnOrderRetail] [varchar](50) NULL,
[ReceiptUnits] [varchar](50) NULL,
[ReceiptCost] [varchar](50) NULL,
[ReceiptRetail] [varchar](50) NULL,
[PermanentMarkdowns] [varchar](50) NULL,
[ReturnsToVendor] [varchar](50) NULL,
[POSMarkdowns] [varchar](50) NULL,
[TimeFK] [smallint] NULL,
[LocationFK] [int] NULL,
[ItemFK] [int] NULL
) ON [AcademySports_DataFG1]
user578849
quelle
Löschen Sie beim Verschieben "Neue Tabelle, Zeilen in Stapeln verschieben" Zeilen in der Originaltabelle, wenn Sie sie verschieben? Möglicherweise müssen Sie zusätzliche Gymnastik machen, damit der Heap den nicht verwendeten Speicherplatz beim Löschen von Daten freigibt.
Zwei
Könnte von Interesse sein, warum ein nicht gruppierter Index in diesem Fall nicht akzeptabel ist. [Ja, ich bin mir der Unterschiede / Vorteile von Clustered und Non-Clustered bewusst. Ich bin nur neugierig, warum Sie einen Nicht-Clustered-Index ausgeschlossen haben.] Verfügt die Tabelle bereits über nicht gruppierte Indizes und wenn ja, wie viel Speicherplatz verwenden sie? [Sie fragen sich, ob durch das Löschen aktueller nicht gruppierter Indizes möglicherweise genügend Speicherplatz für die Erstellung des gruppierten Index frei wird?]
markp-fuso
Haben Sie versucht, den Index mit zu erstellen DATA_COMPRESSION=NONE? Wenn das funktioniert, können Sie anschließend komprimieren.
Dan Guzman
nette Frage.Ich google es.und lese dies ist, was sie sagten dba.stackexchange.com/questions/11956/… oder stackoverflow.com/questions/2309889/… Dies ist die einzig richtige Antwort.
KumarHarsh
1
Könnten Sie, um sicherzugehen, die tatsächliche Fehlermeldung angeben, mit der es fehlschlägt?
RDFozz

Antworten:

3

Wenn Sie kurzfristig Speicherplatz benötigen, besteht eine Option darin:

  1. Verkleinern Sie tempdb vorübergehend, um so viel Speicherplatz auf diesem Laufwerk freizugeben, wie sicher erscheint.
  2. Erstellen Sie eine sekundäre Datendatei für die Datenbank, in der sich die Tabelle auf dem Tempdb-Laufwerk befindet.
  3. Fügen Sie den Clustered-Index zur Tabelle hinzu.
  4. Verkleinern Sie die sekundäre Datei, indem Sie alle Daten daraus migrieren.
  5. Entfernen Sie die sekundäre Datei.
  6. Stellen Sie sicher, dass die Tempdb-Datei auf ihre frühere Größe anwachsen darf.
  7. Erstellen Sie Indizes in der Datenbank der Tabelle neu (das Entfernen der sekundären Datei hat zu einer gewissen Fragmentierung geführt).

HINWEIS: Wie andere vorgeschlagen haben, würde ich dies erst tun, nachdem beispielsweise nicht gruppierte Indizes vorübergehend aus der betreffenden Tabelle entfernt wurden. Dies ermöglicht insbesondere das schnellere Hinzufügen des Clustered-Index, da die nicht-Clustered-Indizes ohnehin alle neu erstellt werden müssten (bei einem Clustered-Index wird der Indexschlüssel verwendet, um die Zeilen in der Tabelle selbst zu lokalisieren). .

Das ist eigentlich ein weiterer Punkt - wie breit ist der Schlüssel im Clustered-Index? Wenn Sie nicht gruppierte Indizes haben und der Schlüssel im gruppierten Index erheblich breiter ist als der Zeiger auf den Heap, verbrauchen die nicht gruppierten Indizes nach der Erstellung des gruppierten Index mehr Speicherplatz.

Wenn der Clusterschlüssel aus mehreren Spalten oder sogar einer großen Spalte besteht (z. B. einer varcharSpalte mit einer durchschnittlichen Länge von 25 oder mehr), sollten Sie stattdessen einen Ersatzschlüssel in Betracht ziehen (normalerweise einen monoton ansteigenden Wert, um die beste INSERTLeistung zu erzielen.

RDFozz
quelle
1

Was Ihren Speicherplatz ausfüllt, ist Ihre Mega-Sortierung (Sie versuchen, alle Ihre 104 GB in einem Ganzen zu sortieren). Ich denke, es kann gelöst werden, indem Sie kleinere Portionen sortieren. Ich empfehle Ihnen, die neue Clustertabelle zu erstellen und die Daten in kleinen Blöcken wie folgt einzufügen:

declare @rowcount int = 1;
while @rowcount > 0
begin
  delete top (5000) 
  from your_heap with(tablock) 
      output deleted.field1, ..., deleted.fieldN 
      into new_clustered_table;
  set @rowcount = @@rowcount;
end; 

Auf diese Weise sortieren Sie jeweils nur 5000 Zeilen. Das einzige Problem sind Seitenteile, die nicht vermieden werden können, da Sie keine sortierte Einfügung vornehmen. Wenn Sie fertig sind, wird die new_clustered_table fragmentiert, aber Sie können sie anschließend neu erstellen.

sepupic
quelle
Ja, Sie haben Recht, ich habe meine Antwort aktualisiert, aber es war nur eine Idee.
Sepupic
0

Nur ein kurzer Tipp: Ziehen Sie in Betracht, alle nicht gruppierten Indizes (falls vorhanden) auf diesem Heap zu löschen, bevor Sie versuchen, einen gruppierten Index zu erstellen. Sie können diese Nicht-CI-Dateien zusammen mit den Details der Include-Spalten skripten und später mit dieser Definition erneut erstellen, nachdem der Clustered-Index erfolgreich erstellt wurde.

Channdeep Singh
quelle