Wann sollte ein Primärschlüssel als nicht gruppiert deklariert werden?

169

Beim Erstellen einer Testdatenbank für eine andere Frage, die ich zuvor gestellt habe, fiel mir ein, dass ein Primärschlüssel deklariert werden konnte NONCLUSTERED

Wann würden Sie einen NONCLUSTEREDPrimärschlüssel anstelle eines CLUSTEREDPrimärschlüssels verwenden?

Danke im Voraus

Stuart Blackler
quelle

Antworten:

187

Die Frage lautet nicht "Wann sollte die PK NC sein?", Sondern "Was ist der richtige Schlüssel für den Clustered-Index?".

Und die Antwort hängt wirklich davon ab, wie Sie die Daten abfragen . Der Clustered-Index hat einen Vorteil gegenüber allen anderen Indizes: Da er immer alle Spalten enthält, ist er immer abdeckend. Daher müssen Abfragen, die den Clustered-Index nutzen können, keine Lookups verwenden, um einige der projizierten Spalten und / oder Prädikate zu erfüllen.

Ein weiteres Puzzleteil ist, wie ein Index verwendet werden kann . Es gibt drei typische Muster:

  • Prüfpunkte, wenn ein einzelner Schlüsselwert im Index gesucht wird
  • Bereichsscans, wenn ein Bereich von Schlüsselwerten abgerufen wird
  • Auftrag nach Anforderungen, wenn ein Index einen Auftrag erfüllen kann, für den keine Stop-and-Go-Sortierung erforderlich ist

Wenn Sie also Ihre erwartete Auslastung (die Abfragen) analysieren und feststellen, dass eine große Anzahl von Abfragen einen bestimmten Index verwenden würde, weil sie ein bestimmtes Zugriffsmuster verwenden, das von einem Index profitiert, ist es sinnvoll, diesen Index als Clustered-Index vorzuschlagen.

Ein weiterer Faktor ist, dass der gruppierte Indexschlüssel der von allen nicht gruppierten Indizes verwendete Nachschlageschlüssel ist und daher ein breiter gruppierter Indexschlüssel einen Welligkeitseffekt erzeugt und alle nicht gruppierten Indizes verbreitert. Breite Indizes bedeuten mehr Seiten, mehr E / A , mehr Gedächtnis, weniger Güte.

Ein guter Clustered-Index ist stabil und ändert sich während der Lebensdauer der Entität nicht, da eine Änderung der Clustered-Index-Schlüsselwerte bedeutet, dass die Zeile gelöscht und wieder eingefügt werden muss.

Und ein guter Clustered-Index wächst nicht zufällig (jeder neu eingefügte Schlüsselwert ist größer als der vorhergehende), um Seitenteile und Fragmentierung zu vermeiden (ohne mit FILLFACTORs herumzuspielen ).

Nachdem wir nun wissen, was ein guter Clustered-Index-Schlüssel ist, entspricht der Primärschlüssel (eine logische Datenmodellierungseigenschaft) den Anforderungen? Wenn ja, sollte die PK geclustert werden. Wenn nein, sollte die PK nicht geclustert sein.

Betrachten Sie zum Beispiel eine Sales Facts-Tabelle. Jeder Eintrag hat eine ID, die der Primärschlüssel ist. Aber die überwiegende Mehrheit der Anfragen nach Daten zwischen einem Zeitpunkt stellen und einem anderen Termine, damit die besten gruppierten Indexschlüssel wären das Verkaufsdatum , nicht die ID . Ein weiteres Beispiel dafür, dass der Clustered-Index vom Primärschlüssel abweicht, ist ein Schlüssel mit sehr geringer Selektivität, wie z. B. eine Kategorie oder ein Status, ein Schlüssel mit nur sehr wenigen unterschiedlichen Werten. Ein gruppierter Indexschlüssel mit diesem Schlüssel mit geringer Selektivität als äußerster linker Schlüssel ist beispielsweise (state, id)häufig sinnvoll, da bei Bereichsüberprüfungen nach allen Einträgen in einem bestimmten "Status" gesucht wird.

Ein letzter Hinweis zur Möglichkeit eines nicht gruppierten Primärschlüssels über einen Heap (dh es gibt überhaupt keinen gruppierten Index). Dies kann ein gültiges Szenario sein. Der typische Grund dafür ist, dass die Leistung von Masseneinfügungen kritisch ist, da Heaps im Vergleich zu Clustered-Indizes einen erheblich besseren Durchsatz von Masseneinfügungen aufweisen.

Remus Rusanu
quelle
1
Was bedeutet hier "Sortieren nach Anforderungen, wenn ein Index eine Bestellung ohne Stop-and-Go-Sortierung erfüllen kann"?
Mike Sherrill 'Cat Recall'
2
@RemusRusanu. +1 Sehr nützliche Antwort. Eine Frage zum Beispiel (state, id). In diesem Beispiel wird die Anforderung "Guter Clustered-Index wächst nicht zufällig" nicht erfüllt, nicht wahr? Können wir es also als guten Clustered-Index betrachten?
Lijo
26

Der Grund für die Verwendung von Clustered-Indizes ist in Wikipedia angegeben :

Durch Clustering wird der Datenblock in eine bestimmte Reihenfolge gebracht, die mit dem Index übereinstimmt, sodass die Zeilendaten in der angegebenen Reihenfolge gespeichert werden. Daher kann für eine bestimmte Datenbanktabelle nur ein Clustered-Index erstellt werden. Clustered-Indizes können die Abrufgeschwindigkeit insgesamt erheblich erhöhen, in der Regel jedoch nur, wenn nacheinander in der gleichen oder umgekehrten Reihenfolge wie der Clustered-Index auf die Daten zugegriffen wird oder wenn ein Bereich von Elementen ausgewählt wird.

Angenommen, ich habe eine Tabelle mit Personen, und diese Personen haben eine Länderspalte und einen eindeutigen Primärschlüssel. Es ist eine demografische Tabelle, das sind also die einzigen Dinge, die mir wichtig sind. Welches Land und wie viele einzigartige Menschen sind an dieses Land gebunden.

Ich werde also immer nur WO AUSWÄHLEN oder NACH LÄNDERN BESTELLEN. Ein Clustered-Index für den Primärschlüssel hilft mir nicht weiter. Ich greife nicht über PK auf diese Daten zu, sondern über diese andere Spalte. Da eine Tabelle nur einen Clustered-Index enthalten kann, kann ich keinen Clustered-Index für ein Land verwenden, wenn ich meine PK als Clustered deklariere.

Außerdem finden Sie in diesem Artikel einen guten Überblick über Clustered- und Nonclustered-Indizes. In SQL Server 6.5 treten bei Clustered-Indizes Probleme mit der Einfügeleistung auf (was hoffentlich für die meisten von uns hier nicht relevant ist).

Wenn Sie einen Clustered-Index in eine IDENTITY-Spalte einfügen, werden alle Ihre Einfügungen auf der letzten Seite der Tabelle vorgenommen - und diese Seite wird für die Dauer jeder IDENTITY gesperrt. Keine große Sache ... es sei denn, Sie haben 5000 Leute, die alle die letzte Seite wollen. Dann haben Sie eine Menge Streit um diese Seite

Beachten Sie, dass dies in späteren Versionen nicht der Fall ist.

Ben Brocka
quelle
3
FIY, Sie haben SQL Server 6.5 erwähnt: dba.stackexchange.com/questions/1584/…
gbn
15

Wenn es sich bei Ihrem Primärschlüssel UNIQUEIDENTIFIERum den handelt, müssen Sie diesen angeben NONCLUSTERED. Wenn Sie es zu einem Cluster zusammenfassen, muss jede Einfügung eine Reihe von Datensätzen mischen, um die neue Zeile an der richtigen Position einzufügen. Dies wird die Leistung des Panzers verbessern.

Bryan Johns
quelle
1
Während ich versuche, UUIDs für gruppierte Schlüssel zu vermeiden, glaube ich, dass die oben genannte Begründung möglicherweise unvollständig ist. SQL Server mischt nicht unbedingt die Zeilen neu, um a an der richtigen Position einzufügen (wenn Sie "zwischen dem niedrigeren und dem höheren Wert" meinen). Betrachten Sie eine Einfügung in die Mitte einer Billionen-Zeilentabelle. Es ist eine zusätzliche Indirektion erforderlich, was Sie möglicherweise gemeint haben. Es gibt auch einen sequentiellen UNIQUEIDENTIFIERTyp, der mit der gleichen Wahrscheinlichkeit eindeutige Schlüssel generiert, obwohl er immer noch eine Größe von 128 hat.
Charles Burns
7

Ein sehr verbreitetes Beispiel:

  • CustomerTisch mit CustomerIDalsCLUSTERED PRIMARY KEY
  • Bestelltabelle mit OrderID (PK), CustomerID, OrderDateund einigen anderen Spalten
  • OrderPositions mit OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • Sie müssen die Auftragstabellen indizieren

Natürlich ist "es kommt darauf an" - wie fast immer - die richtige Antwort, aber die meisten Anwendungen (nicht BI-Reports) funktionieren kundenbasiert (z. B. Sie melden sich als Kunde 278 auf der Website an und klicken auf "Meine Bestellungen" oder Der Sachbearbeiter listet alle Bestellungen für den Kunden 4569 auf, oder Ihre Rechnungsroutine summiert alle Bestellungen für den Kunden 137).

In diesem Fall wäre es nicht sinnvoll, die Tabelle nach dem zu gruppieren OrderID. Ja, Sie werden Fragen haben, SELECT ... WHERE OrderId = ?um die Bestelldetails aufzulisten, aber dies wäre normalerweise eine kurze und billige Indexsuche (3 Lesevorgänge).

Wenn Sie andererseits Ihre OrderTabelle nach dem gruppieren würden CustomerID, müssten Sie nicht jedes Mal mehrere Schlüsselsuchen durchführen , wenn Sie die Tabelle abfragen CustomerId = ?.

Das CLUSTERED INDEXsollte immer so sein UNIQUE, sonst würde SQL Server eine unsichtbare (= nicht verwendbare) INT-Spalte hinzufügen UNIQUIFIER, um die Eindeutigkeit sicherzustellen - und es wäre viel sinnvoller, echte (verwendbare) Daten hinzuzufügen, als zufällige (abhängig von der Einfügereihenfolge) Daten.

Da ein Kunde (hoffentlich) mehr als eine Bestellung aufgeben wird , müssten wir entweder die OrderIDoder (falls Sie dies normalerweise sortieren) die OrderDate(falls es sich um eine Datumszeit handelt - ansonsten wäre der Kunde auf eine Bestellung pro Tag beschränkt) hinzufügen das CLUSTERED INDEXund am Ende mit:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

Die gleichen Regeln gelten für die OrderPositionsTabelle. In der Regel werden in den meisten Abfragen alle Positionen für eine bestimmte Reihenfolge aufgelistet. Daher sollten Sie die PK mit dem Buchstaben OrderPositionIDas NONCLUSTEREDund a UNIQUE CLUSTERED INDEXon erstellen OrderId, OrderPositionID.

Übrigens: Es ist richtig, dass die CustomerTabelle von ihrer PK geclustert wird ( CustomerIDda es sich um eine "Top-Level-Tabelle" handelt) und in einer typischen Anwendung meistens von ihrer CustomerID abgefragt wird.

Reine Lookup - Tabellen , wie zB Gendersoder InvoiceTypesoder PaymentTypesind ein weiteres Beispiel für Tabellen , die durch seine PK geclustert werden sollen (weil Sie in der Regel kommen sie auf GenderId, InvoiceTypeIdoder PaymentTypeId).

Thomas Franz
quelle
2

Wenn ein Clustered-Index für das Gesamtsystem vorteilhafter ist als eine Clustered-PK, indem ein Leistungsmaß verwendet wird. Es kann nur einen Clustered-Index für eine Tabelle geben.

Beispielhafte Leistungsindikatoren sind die einzelne Abfragezeit (Geschwindigkeit), die Integration der gesamten Abfragezeiten für die Tabelle (Effizienz) und das Hinzufügen vieler Include-Spalten zu einem sehr großen, nicht gruppierten Index, um eine Leistung zu erzielen, die der gruppierten (Größe) ähnelt ).

Dies kann vorkommen, wenn Daten im Allgemeinen mit einem Index abgerufen werden, der nicht eindeutig ist, Nullen enthält (in einer PK nicht zulässig) oder die PK aus einem sekundären Grund hinzugefügt wurde (z. B. Replikation oder Identifizierung von Audit-Trail-Datensätzen).

crokusek
quelle