Clustered vs Non-Clustered

98

Meine SQL-Kenntnisse auf niedrigerer Ebene (Server 2008) sind begrenzt und werden jetzt von unseren Datenbankadministratoren gefordert. Lassen Sie mich das Szenario erklären (ich habe offensichtliche Aussagen in der Hoffnung erwähnt, dass ich Recht habe, aber wenn Sie etwas falsch sehen, sagen Sie es mir bitte):

Wir haben einen Tisch, der 'Gerichtsbeschlüsse' für Menschen enthält. Als ich die Tabelle (Name: CourtOrder) erstellt habe, habe ich sie wie folgt erstellt:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Ich habe dann einen nicht gruppierten Index auf den Primärschlüssel angewendet (aus Effizienzgründen). Meine Gründe sind, dass es sich um ein eindeutiges Feld (Primärschlüssel) handelt und wie häufig indiziert werden sollte, hauptsächlich zu AuswahlzweckenSelect from table where primary key = ...

Ich habe dann einen CLUSTERED-Index auf PersonId angewendet. Der Grund war, Bestellungen für eine bestimmte Person physisch zu gruppieren, da die überwiegende Mehrheit der Arbeit darin besteht, Bestellungen für eine Person zu erhalten. So,select from mytable where personId = ...

Ich bin jetzt darüber aufgezogen worden. Mir wurde gesagt, dass wir den Clustered-Index auf den Primärschlüssel und den normalen Index auf die personId setzen sollen. Das kommt mir sehr seltsam vor. Warum sollten Sie zunächst einen Clustered-Index für eine eindeutige Spalte erstellen? Was ist es Clustering? Sicher ist das eine Verschwendung des Clustered-Index? Ich hätte geglaubt, dass ein normaler Index für eine eindeutige Spalte verwendet wird. Das Clustering des Index würde auch bedeuten, dass wir keine andere Spalte gruppieren können (eine pro Tabelle, richtig?).

Der Grund dafür, dass mir mitgeteilt wurde, dass ich einen Fehler gemacht habe, ist, dass sie glauben, dass das Einfügen eines Clustered-Index in die PersonId das Einfügen verlangsamen würde. Für den Geschwindigkeitszuwachs von 5% einer Auswahl würden wir eine 95% ige Geschwindigkeitsverschlechterung bei Einfügungen und Aktualisierungen erhalten. Ist das richtig und gültig?

Sie sagen, dass SQL Server, da wir die personId gruppieren, Daten neu anordnen muss, wenn wir die PersonId einfügen oder ändern.

Dann habe ich gefragt, warum SQL das Konzept eines CLUSTERED INDEX haben sollte, wenn es so langsam ist. Ist es so langsam wie sie sagen? Wie sollte ich meine Indizes einrichten, um eine optimale Leistung zu erzielen? Ich hätte gedacht, dass SELECT mehr als INSERT verwendet wird ... aber sie sagen, dass wir Probleme beim Sperren von INSERTS haben ...

Hoffe jemand kann mir helfen.

Craig
quelle

Antworten:

117

Der Unterschied zwischen einem Clustered-Index und einem Nicht-Clustered-Index besteht darin, dass der Clustered-Index die physische Reihenfolge der Zeilen in der Datenbank bestimmt . Mit anderen Worten PersonIdbedeutet das Anwenden des Clustered-Index auf , dass die Zeilen PersonIdin der Tabelle physisch sortiert werden , sodass eine Indexsuche in dieser Zeile direkt zur Zeile führt (und nicht zu einem nicht gruppierten Index, der Sie zu den Zeilen führt Ort, einen zusätzlichen Schritt hinzufügen).

Es ist jedoch ungewöhnlich, dass der Primärschlüssel nicht der Clustered-Index ist, aber nicht unbekannt. Das Problem mit Ihrem Szenario ist eigentlich das Gegenteil von dem, was Sie annehmen: Sie möchten eindeutige Werte in einem Clustered-Index, keine Duplikate. Da der Clustered-Index die physische Reihenfolge der Zeile bestimmt, muss der Server Zeilen mit einem doppelten Schlüsselwert (in Ihrem Fall alle Zeilen mit demselben) einen Hintergrundwert hinzufügen, wenn sich der Index in einer nicht eindeutigen Spalte befindet PersonId), so dass der kombinierte Wert (Schlüssel + Hintergrundwert) eindeutig ist.

Das einzige, was ich vorschlagen würde, ist, nicht einen Ersatzschlüssel (Ihre CourtOrderId) als Primärschlüssel zu verwenden, sondern einen zusammengesetzten Primärschlüssel der PersonIdund einer anderen eindeutig identifizierenden Spalte oder eines Satzes von Spalten. Wenn dies jedoch nicht möglich (oder nicht praktikabel) ist, setzen Sie den Clustered-Index auf CourtOrderId.

Adam Robinson
quelle
Danke Adam. Wann wäre dann ein Clustered-Index nützlich? Ich dachte, der Vorteil eines Clustered-Index besteht darin, die Daten zu gruppieren, beispielsweise wenn sich die meisten Abfragen auf einer PersonID befinden ... also würden die Daten gruppiert.
Craig
3
Es ist nicht physisch sortiert nach PersonId. Es ist logisch sortiert nach PersonId, jede Diskrepanz zwischen logischer und physischer Reihenfolge ist der Grad der logischen Fragmentierung.
Martin Smith
1
@cdotlister Der Vorteil eines Index besteht darin, die Daten zu sortieren und nicht zu gruppieren (was doppelte Daten innerhalb des Index impliziert). Während die Unterscheidung semantisch erscheinen mag, ist dies bei Clustered-Indizes nicht der Fall. Wenn möglich, sollte sich der Clustered-Index auf etwas befinden, das die Zeile eindeutig identifiziert, und (idealerweise) auch die am häufigsten abgefragte Spalte oder Gruppe von Spalten. Aus diesem Grund befindet es sich normalerweise auf dem Primärschlüssel.
Adam Robinson
1
@CyberSluethOmega: Ich weiß es nicht; Ihre Frage enthält nicht genügend Informationen, damit ich eine Entscheidung treffen kann. Möchte ich einen Clustered-Index für eine Reihe von Spalten, in denen häufig Zeilen hinzugefügt oder gelöscht werden, außer am Ende der Tabelle ? Nein, aber ich bin mir nicht sicher, warum Sie das fragen oder warum die Abstimmung.
Adam Robinson
1
@CyberSluethOmega: Das Internet kann Kommentare defensiv oder kalt klingen lassen, wenn sie nicht so gedacht sind. Sie haben behauptet, ich hätte gesagt, dass ich keine Umstände kenne, unter denen der Clustered-Index etwas anderes als der Primärschlüssel ist, obwohl ich tatsächlich nichts dergleichen gesagt habe. In der Tat, was ich sagte , war : „Das ist ungewöhnlich ..., aber nicht unerhört“, was bedeutet , dass ich sie von Fällen, wo dies geschehen ist.
Adam Robinson
14

Ich bin auf keinen Fall ein SQL-Experte. Nehmen Sie dies also eher als Entwickleransicht als als DBA-Ansicht.

Einfügungen in gruppierten (physisch geordneten) Indizes, die nicht in sequentieller Reihenfolge vorliegen, verursachen zusätzliche Arbeit für Einfügungen / Aktualisierungen. Wenn mehrere Einfügungen gleichzeitig ausgeführt werden und alle am selben Ort ausgeführt werden, kommt es zu Konflikten. Ihre spezifische Leistung hängt von Ihren Daten und dem Zugriff darauf ab. Die allgemeine Faustregel lautet, dass Sie Ihren Clustered-Index auf dem eindeutigsten schmalen Wert in Ihrer Tabelle (normalerweise der PK) erstellen.

Ich gehe davon aus, dass sich Ihre PersonId nicht ändert, sodass hier keine Updates ins Spiel kommen. Betrachten Sie jedoch einen Schnappschuss einiger Zeilen mit der PersonId 1 2 3 3 4 5 6 7 8 8

Fügen Sie nun 20 neue Zeilen für PersonId von 3 ein. Da dies kein eindeutiger Schlüssel ist, fügt der Server Ihrem Wert (hinter den Kulissen) einige zusätzliche Bytes hinzu, um ihn eindeutig zu machen (wodurch auch zusätzlicher Speicherplatz hinzugefügt wird), und dann den Ort, an dem Diese werden sich ändern müssen. Vergleichen Sie dies mit dem Einfügen einer automatisch inkrementierenden PK, bei der die Einfügungen am Ende erfolgen. Die nicht-technische Erklärung würde wahrscheinlich darauf zurückzuführen sein: Es ist weniger Arbeit zum Mischen von Blättern erforderlich, wenn am Ende der Tabelle auf natürliche Weise höhere Werte erreicht werden als beim Einfügen Ihrer Elemente die Position der vorhandenen Elemente an dieser Position überarbeitet wird.

Wenn Sie Probleme mit Einfügungen haben, fügen Sie wahrscheinlich eine Reihe derselben (oder ähnlicher) PersonId-Werte gleichzeitig ein, was diese zusätzliche Arbeit an verschiedenen Stellen in der Tabelle verursacht und die Fragmentierung Sie umbringt. Der Nachteil des Wechsels zu der PK, die in Ihrem Fall geclustert wird, besteht darin, dass Sie heute Einfügeprobleme bei PersonIds haben, deren Wert in der Tabelle verteilt ist, wenn Sie Ihren Clustered-Index auf die PK umstellen und alle Einfügungen jetzt in einer erfolgen Ort, dann kann sich Ihr Problem aufgrund der erhöhten Konfliktkonzentration tatsächlich verschlimmern. (Auf der anderen Seite wird Ihr Problem wahrscheinlich behoben, wenn Ihre Einfügungen heute nicht über alle Bereiche verteilt sind, sondern in der Regel in ähnlichen Bereichen zusammengefasst sind, indem Sie Ihren Clustered-Index von PersonId auf Ihre PK umstellen, da Sie die Anzahl der Einfügungen minimieren Zersplitterung.)

Ihre Leistungsprobleme sollten auf Ihre individuelle Situation hin analysiert werden und diese Art von Antworten nur als allgemeine Richtlinien verwenden. Am besten verlassen Sie sich auf einen DBA, der genau überprüft, wo Ihre Probleme liegen. Es hört sich so an, als hätten Sie Probleme mit Ressourcenkonflikten, die über eine einfache Indexoptimierung hinausgehen könnten. Dies könnte ein Symptom für ein viel größeres Problem sein. (Wahrscheinlich Designprobleme ... sonst Ressourcenbeschränkungen.)

Auf jeden Fall viel Glück!

Darian Miller
quelle
5

Einige Autoren schlagen nicht die „verschwenden“ CIauf einer identitySäule , wenn es eine Alternative , die Bereichsabfragen profitieren würde.

Aus den MSDN Clustered Index Design Guidelines sollte der Schlüssel gemäß den folgenden Kriterien ausgewählt werden

  1. Kann für häufig verwendete Abfragen verwendet werden.
  2. Bieten Sie ein hohes Maß an Einzigartigkeit.
  3. Kann in Bereichsabfragen verwendet werden.

Ihre CourtOrderIDKolumne trifft sich 2. Ihre PersonIdTreffen 1und 3. Da die meisten Zeilen uniqueifierohnehin hinzugefügt werden, können Sie es genauso gut als eindeutig deklarieren und verwenden, PersonId,CourtOrderIDda dies dieselbe Breite hat, aber nützlicher ist, da der Clustered-Indexschlüssel allen NCIs als Zeilenlokator hinzugefügt wird und dies ermöglicht sie, um mehr Fragen zu decken.

Das Hauptproblem bei der Verwendung PersonId,CourtOrderIDals CI besteht darin, dass wahrscheinlich eine logische Fragmentierung auftritt (und dies wirkt sich insbesondere auf die Bereichsabfragen aus, denen Sie helfen möchten), sodass Sie den Füllfaktor und die Fragmentierungsstufen überwachen und die Indexwartung häufiger durchführen müssen.

Martin Smith
quelle
3

Dies wird unter folgendem Link erläutert: https://msdn.microsoft.com/en-us/ms190457.aspx

Clustered

  • Clustered-Indizes sortieren und speichern die Datenzeilen in der Tabelle oder Ansicht basierend auf ihren Schlüsselwerten. Dies sind die Spalten, die in der Indexdefinition enthalten sind. Es kann nur einen Clustered-Index pro Tabelle geben, da die Datenzeilen selbst nur in einer Reihenfolge sortiert werden können.

  • Die Datenzeilen in einer Tabelle werden nur dann in sortierter Reihenfolge gespeichert, wenn die Tabelle einen Clustered-Index enthält. Wenn eine Tabelle einen Clustered-Index hat, wird die Tabelle als Clustered-Tabelle bezeichnet. Wenn eine Tabelle keinen Clustered-Index hat, werden ihre Datenzeilen in einer ungeordneten Struktur gespeichert, die als Heap bezeichnet wird.

Nicht gruppiert

  • Nicht gruppierte Indizes haben eine von den Datenzeilen getrennte Struktur. Ein nicht gruppierter Index enthält die nicht gruppierten Indexschlüsselwerte, und jeder Schlüsselwerteintrag verfügt über einen Zeiger auf die Datenzeile, die den Schlüsselwert enthält .

  • Der Zeiger von einer Indexzeile in einem nicht gruppierten Index auf eine Datenzeile wird als Zeilenlokator bezeichnet. Die Struktur des Zeilenlokators hängt davon ab, ob die Datenseiten in einem Heap oder einer Clustertabelle gespeichert sind. Bei einem Heap ist ein Zeilenlokator ein Zeiger auf die Zeile. Bei einer Clustertabelle ist der Zeilenlokator der Clustered-Indexschlüssel.

  • Sie können der Blattebene des nicht gruppierten Index Spalten ohne Schlüssel hinzufügen, um vorhandene Indexschlüsselgrenzen, 900 Byte und 16 Schlüsselspalten zu umgehen und vollständig abgedeckte, indizierte Abfragen auszuführen.

user2191454
quelle
-3

Einige Datenbanken mit einigen bösen Auswahlen schließen sich einer gespeicherten Prozedur an - nur der Unterschied ist der Index

INDEXE - gruppiert gegen nicht gruppiert

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
quelle