Wichtige Überlegungen
Ich sehe einen wichtigen Vorteil für Heaps und einen für gruppierte Tabellen sowie eine dritte Überlegung, die in beide Richtungen gehen kann.
Ein Haufen erspart Ihnen eine Indirektionsebene. Indizes enthalten Zeilen-IDs, die direkt (also nicht wirklich, aber so direkt wie möglich) auf einen Speicherort verweisen. Daher sollte eine Indexsuche für einen Heap ungefähr die Hälfte einer nicht gruppierten Indexsuche für eine gruppierte Tabelle kosten.
Ein Clustered-Index wird per se dank eines (fast) freien Index sortiert. Da sich der Clustering-Index in der physischen Reihenfolge der Daten widerspiegelt, nimmt er relativ wenig Platz über den eigentlichen Daten selbst ein, was Sie natürlich trotzdem speichern müssen. Aufgrund der physischen Reihenfolge kann ein Entfernungsscan anhand dieses Index sehr effizient nach dem Startpunkt suchen und dann bis zum Endpunkt zippen.
Heap-Indizes verweisen auf 64-Bit-RIDs. Wie bereits erwähnt, verweisen die nicht gruppierten Indizes in einer gruppierten Tabelle auf den Clustering-Schlüssel, der kleiner (32 Bit INT
), gleich (64 Bit BIGINT
) oder größer (48 Bit DATETIME2()
plus 32 Bit) sein INT
kann. oder eine 128-Bit-GUID). Offensichtlich führt eine breitere Referenz zu größeren und teureren Indizes.
Platzanforderungen
Mit diesen beiden Tabellen:
CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)
CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)
... jeder mit 8,7 M Datensätzen bestückt war, war der Speicherplatz 150 MB für Daten für beide; 120 MB für die Indizes der gruppierten Tabelle, 310 MB für die Indizes der nicht gruppierten Tabelle. Dies spiegelt wider, dass der Clustered-Index enger ist als eine RID, und dass der Clustering-Index meistens ein "Werbegeschenk" ist. Wenn die eindeutigen Indizes nicht ID2
aktiviert sind, sinkt der erforderliche Indexspeicherplatz für die nicht gruppierte Tabelle auf 155 MB (die Hälfte, wie zu erwarten), für die gruppierte PK jedoch auf nur 150 KB - nahezu nichts.
Ein nicht gruppierter Index eines 32-Bit-Felds in einer gruppierten Tabelle mit einem 32-Bit-Index (nominell insgesamt 64 Bit) nahm also 120 MB in Anspruch, während ein Index eines 32-Bit-Felds in einem Heap mit 64 Bit RID (insgesamt 96 Bit, nominell) nahm 155 MB in Anspruch, etwas weniger als die erwartete Steigerung um 50% von 64-Bit- auf 96-Bit-Schlüssel, aber es gibt natürlich einen Mehraufwand, der den effektiven Größenunterschied verringert.
Das Auffüllen der beiden Tabellen und das Erstellen ihrer Indizes dauerte für jede Tabelle gleich lange. Bei einfachen Tests mit Scans oder Suchvorgängen habe ich keine wesentlichen Leistungsunterschiede zwischen den Tabellen festgestellt, die mit dem Microsoft-Whitepaper übereinstimmen, das von gbn hilfreich verlinkt wurde. Das genannte Papier zeigt einen signifikanten Unterschied für den hochgradig gleichzeitigen Zugriff; Ich bin mir nicht sicher, warum das passiert, hoffentlich jemand mit mehr Erfahrung, als ich mit hochvolumigen OLTP-Systemen sagen kann.
Das Hinzufügen von ~ 40 Bytes zufälliger Daten variabler Länge änderte diese Äquivalenz nicht nennenswert. Das Ersetzen der INT
s durch breite UUIDs war ebenfalls nicht der Fall (jede Tabelle wurde in etwa gleichem Maße verlangsamt). Ihr Kilometerstand kann variieren, aber in den meisten Fällen ist es wichtiger, ob ein Index verfügbar ist als welche.
Krimskrams
Um einen Bereichsscan für einen nicht gruppierten Index durchzuführen - entweder weil die Tabelle ein Heap ist oder der Index nicht der gruppierte Index -, müssen Sie den Index scannen und dann für jeden Treffer eine Suche nach der Tabelle durchführen. Dies kann sehr teuer sein, daher ist es manchmal billiger, nur den Tisch zu scannen. Sie können dies jedoch mit einem Deckungsindex umgehen. Dies gilt unabhängig davon, ob Sie Ihre Tabelle geclustert haben oder nicht.
Wie @gbn hervorhob, gibt es keine einfache Möglichkeit, einen Haufen zu komprimieren. Wenn sich Ihre Tabelle jedoch im Laufe der Zeit allmählich vergrößert - ein sehr häufiger Fall -, entsteht wenig Verschwendung, da der durch Löschvorgänge freiwerdende Speicherplatz durch neue Daten gefüllt wird.
Einige der Diskussionen zwischen Heap und gruppierten Tabellen haben ein merkwürdiges Argument von Strawman geliefert, wonach ein Heap ohne Indizes einer gruppierten Tabelle dahingehend unterlegen ist, dass immer ein Tabellenscan erforderlich ist. Dies ist sicherlich richtig, aber der aussagekräftigere Vergleich ist "große gut indizierte Clustertabelle" mit "großer gut indizierter Heap". Wenn Ihre Tabelle sehr klein ist oder Sie immer Tabellenscans durchführen, spielt es keine Rolle, ob Sie sie gruppieren oder nicht.
Da jeder Index in einer Clustered-Tabelle auf den Clustering-Index verweist, werden praktisch alle Indizes abgedeckt. Eine Abfrage, die auf eine indizierte Spalte und die Cluster-Spalte (n) verweist, kann einen Index-Scan ohne Tabellensuche durchführen. Dies ist im Allgemeinen nicht sinnvoll, wenn es sich bei Ihrem Clustering-Index um einen synthetischen Schlüssel handelt. Wenn es sich jedoch um einen Geschäftsschlüssel handelt, den Sie ohnehin abrufen müssen, ist dies eine nette Funktion.
TL; DR
Ich bin ein Data Warehousing-Typ, kein OLTP-Experte. Für Faktentabellen verwende ich fast immer einen Clustering-Index für das Feld, für das meistens Bereichsscans erforderlich sind, normalerweise ein Datumsfeld. Für Dimensionstabellen gruppiere ich sie auf der PK, damit sie für Zusammenführungsverknüpfungen mit Faktentabellen vorsortiert sind.
Es gibt mehrere Gründe, Clustering-Indizes zu verwenden. Wenn jedoch keiner dieser Gründe zutrifft, lohnt sich der Aufwand möglicherweise nicht. Ich vermute, es gibt eine Menge "Wir haben es immer so gemacht" und "es ist nur die beste Praxis", wenn Menschen Clustered-Indizes universell verwenden. Probieren Sie sowohl Ihre Daten als auch Ihre Last aus und sehen Sie, was am besten funktioniert.