Beschleunigen Sie die Erstellung großer Clustered-Indizes?

8

Ich habe eine große Tabelle, die Zeilenanzahl der Tabelle beträgt mehr als 3 Milliarden, der Datenraum für diese Tabelle beträgt ca. 120 GB.

Und Intel Xeon CPU E5645 bei 2,4 GHz (2 Prozessoren), 24 CPUs, 64 G Speicher, 64 Bit Windows Server 2008 R2 Enterprise.

ich renne

create unique clustered index MyTable_IXC on tblFactFoo(barKey) on [PRIMARY]

Es dauerte jedoch mehr als 6 Stunden (tatsächlich wurde nach 6 Stunden ein Fehler beim doppelten Schlüssel gemeldet).

Beim Ausführen betrug die CPU weniger als 10% und die Festplatten-E / A weniger als 20 MB / s, normalerweise etwa 15 MB / s. Ich frage mich, wie die Leistung beim Erstellen eines Clustered-Index mit solch leistungsstarker Hardware verbessert werden kann.

Aaron Bertrand
quelle
Ist das SQL Server Enterprise? Auf welchem ​​Speicher befindet sich die Datenbank?
usr
Ja, SQL Server 2008 R2 Enterprise. Was meinst du mit Lagerung? Nur Festplatte, HP LOGICAL VOLUME SCSI Disk.

Antworten:

4

Sie müssen sich den Wartetyp ansehen, wenn die Abfrage ausgeführt wird. Wahrscheinlich benötigen Sie schnellere Festplatten, da das Erstellen eines Index für eine so große Tabelle zu massiven Lese- und Schreibvorgängen führen wird.

Kurz gesagt, Sie müssen die 120-Gig-Tabelle lesen, sie nach dem Clustering-Schlüssel sortieren (was dazu führen wird, dass Tempdb mit einer Menge Geld verschüttet wird, wahrscheinlich 100 Gigs in Tempdb) und dann den Clustered-Index in die Datenbank schreiben verursacht 120 Gigs von Schreibvorgängen.

Darüber hinaus müssen alle nicht gruppierten Indizes in der Tabelle gleichzeitig neu erstellt werden, sodass auch alle Indizes gelesen und neu geschrieben werden müssen (zusammen mit dem gesamten Speicherverlust, der mit der Neuerstellung der nicht gruppierten Indizes verbunden ist).

Sie können die Dinge beschleunigen, indem Sie die Nicht-Clusterd-Indizes deaktivieren und sie dann manuell erstellen, nachdem der Clustered-Index neu erstellt wurde. Sie sollten sicherstellen, dass Endbenutzer das System nicht berühren können, während die nicht gruppierten Indizes erstellt werden, da ihre Abfrageleistungen bis zur Erstellung der nicht gruppierten Indizes schrecklich sind.

Angenommen, Sie können die häufig verwendeten Indizes erstellen, dann die Benutzer wieder einlassen und dann die anderen Indizes online erstellen, damit die Benutzer arbeiten können.

Egal, was Sie in einem WIRKLICH langen Wartungsfenster sehen, in dem Sie die Festplatten so hart wie möglich zuschlagen.

mrdenny
quelle
3

Hier sind einige Dinge zu bewerten:

  1. Aktivieren Sie die Datenkomprimierung: Es sieht so aus, als wären Sie an E / A gebunden und hätten CPU zu sparen. Datenkomprimierung könnte hier ein guter Kompromiss sein.
  2. Einschalten SORT_IN_TEMPDB. Dies kann die E / A-Muster drastisch verbessern (mehr sequentielle E / A und weniger Fragmentierung im endgültigen Index).
  3. Bauen Sie den Index in eine neue (vordefinierte) Dateigruppe ein. Eine neue Dateigruppe ist nicht fragmentiert, sodass Sie dieses Problem zumindest beseitigen können. Verwenden Sie die sofortige Dateiinitialisierung.

Oder laden Sie die Daten zunächst richtig sortiert. Dann müssen Sie überhaupt keinen Index erstellen. Dies hat gewisse Nachteile, ist aber erwägenswert. Die bestmögliche Lösung wäre das Laden in einen partitionierten Clustered-Index unter Verwendung des ORDERHinweises zum Massenladen. Ein Massenimportstrom pro Partition und eine Partition pro CPU oder pro physischer Festplatte.

usr
quelle
1

Wie ich das persönlich machen würde:

  • Benennen Sie TableA in TableA_Old um und erstellen Sie eine Ansicht mit dem Namen TableA. Auf diese Weise können Ihre Benutzer weiterarbeiten.
  • Erstellen Sie eine neue TabelleB, erstellen Sie Ihre Indizes darauf und beginnen Sie mit dem Kopieren von Daten aus TableA_Old in TabelleB (oder kopieren Sie zuerst Daten und erstellen Sie dann Indizes; zumindest würde ich zuerst den Clustered-Index und alle anderen Indizes erstellen, nachdem die Daten kopiert wurden).
  • Löschen Sie danach die Ansicht TableA, benennen Sie TableB -> TableA um und löschen Sie TableA_Old. Stellen Sie sicher, dass Sie die letzten Datensätze erhalten haben, die in TableA_Old hinzugefügt wurden. Nachteil: Sie benötigen mehr Speicherplatz, aber weniger Ausfallzeiten.
Koen D.
quelle
Ich sehe jetzt, dass DevArt im Grunde die gleiche Antwort hatte wie ich :-)
Koen D
0

Jedes Mal, wenn Sie einen Clusterindex erstellen / neu erstellen, beginnt der Server, Seiten zu bestellen. Dies ist ein sehr ressourcenintensiver Vorgang. Ihr Tisch ist groß. Ich würde Ihnen raten, Ihre Tabelle in mehrere kleinere Tabellen aufzuteilen (dh eine Datennormalisierung durchzuführen), wenn dies möglich ist. Sie können auch eine leere Kopie dieser Tabelle erstellen, einen Clusterindex für eine leere Tabelle hinzufügen, alle Daten aus Ihrer Haupttabelle importieren und anschließend die Haupttabelle löschen.

Ich meine so etwas -

CREATE TABLE dbo.tblFactFoo_New
(
      barKey INT NOT NULL
    , ...
)

CREATE UNIQUE CLUSTERED INDEX tblFactFoo_IXC ON tblFactFoo_New(barKey) ON [PRIMARY]

INSERT INTO dbo.tblFactFoo_New(barKey, ...)
SELECT barKey, ... 
FROM dbo.tblFactFoo
GROUP BY barKey, ... -- without duplicates
ORDER BY barKey

DROP TABLE dbo.tblFactFoo

sp_rename 'dbo.tblFactFoo_New', 'dbo.tblFactFoo'
Devart
quelle
0

Um die Geschwindigkeit eines SQL-Befehls zu erhöhen, sollten Sie über eine ordnungsgemäß eingerichtete Datenbank verfügen. Daher hoffe ich, dass Ihre Datenbank auf einer anderen Festplatte gespeichert ist und sich Master und Tempdb auf einer eigenen Festplatte befinden.

Davon abgesehen gibt es mehrere Faktoren, die die Indexerstellung beeinflussen: Wenn die Tabelle bereits sortiert ist und es so aussieht, als würden Sie diese auf einer HEAP-Tabelle aufbauen, würde ich sagen, dass sie nicht sortiert ist, und die andere Komponente ist der Spaltentyp, nach dem Sie arbeiten erstellen den Index auf. Die in einem Clustered-Index enthaltenen Informationen sind durch die Anzahl der Spalten oder die Bytegröße der Spalten (je nachdem, was zuerst eintritt) begrenzt. Daher sind einige Spalten keine so guten Kandidaten für Clustered-Indizes.

Da Sie einen eindeutigen Index für eine Heap-Tabelle erstellen, sollten Sie diese bereinigen, damit Sie keine doppelten Werte haben. Dadurch müssen Sie den Index nicht erneut erstellen.

Bevor Sie die Indexerstellungsabfrage ausführen, führen Sie diese zuerst aus

SELECT 
   barKey
FROM
(
    SELECT 
        barKey, 
        COUNT(barKey) AS NoOfDuplicates 
    FROM 
        dbo.tblFactFoo WITH(NOLOCK)
    GROUP BY 
        barKey
)
WHERE
NoOfDuplicates > 1;

Nachdem Sie dies ausgeführt und die doppelten Datensätze verarbeitet haben, können Sie Folgendes ausführen. Beachten Sie, dass hierfür zusätzlicher Speicherplatz benötigt wird, sodass Sie mindestens so viel Speicherplatz benötigen wie die Größe dieser Tabelle.

CREATE UNIQUE CLUSTERED INDEX IXC_MyTable ON dbo.tblFactFoo(barKey) WITH(SORT_IN_TEMPDB)
GO

Dadurch wird die Sortierung (die beim Erstellen eines Index erforderlich ist) in der Tempdb-Datenbank erzwungen und anschließend zurück übertragen und Ihre Daten ersetzt.

Eine Alternative wäre, eine doppelte Tabelle mit demselben Namen, denselben Spalten usw. zu erstellen, den Clusterschlüssel hinzuzufügen, bevor Sie Datensätze hinzufügen und dann diesen Befehl ausführen:

MERGE INTO dbo.tblFactFoo AS source
USING dbo.tblFactFooIndexed AS destination ON source.barKey = destination.barKey
WHEN NOT MATCHED BY source THEN
INSERT INTO destination(col1, col2, barKey etc) VALUES (source.col1, source.col2, source.barKey etc)
WHEN MATCHED BY source AND (add extra conditions here if needed) THEN
-- INSERT / UPDATE or DELETE depending on how you want to handle duplicate keys

Da es sich um eine Set-Operation handelt, sollte dies theoretisch viel schneller funktionieren, da der SQL Server mit Sets schneller arbeitet als mit Zeilen. Wenn Sie fertig sind, löschen Sie die erste Tabelle und benennen Sie die zweite Tabelle um.

Sollten Sie weitere Hilfe mit dem Befehl MERGE benötigen, finden Sie hier den Link zu MSDN: http://msdn.microsoft.com/en-us/library/bb510625.aspx

Toni Kostelac
quelle