Identitätsspalte als Clustered Index schlechte Idee?


7

Ich habe nur ein paar Monate in SQL Server programmiert, daher sind meine Kenntnisse in vielerlei Hinsicht nicht gut. In einem bereits vorhandenen Projekt stieß ich auf viele Tabellen mit großen zusammengesetzten Primärschlüsseln mit Clustered-Index. Nach dem, was ich zusammengetragen habe, beeinträchtigt eine große Spalte / zusammengesetzte Spalte mit gruppiertem Index die Leistung sehr stark, und manchmal ist die logische Lösung eine Identitätsspalte. Gleichzeitig bin ich auf viele Menschen gestoßen, die die übermäßige Verwendung von Identitätsspalten in Flammen gesetzt haben.

Aber ich bin noch nie auf ein Beispiel gestoßen, bei dem eine Identitätsspalte eine schlechte Idee ist.

Kürzlich haben wir standardisiert, dass jede Tabelle eine Identitätsspalte als Clustered-Index haben soll - unabhängig davon, ob wir sie als PK verwenden oder nicht, da wir sie für einige Exportzwecke benötigen.

Daher möchte ich einige Beispiele in realen Szenarien, in denen die Verwendung einer Identitätsspalte als Clustered-Index eine schlechte Idee ist.

Obwohl es manchmal unser Leben leichter macht, bin ich nie auf ein Szenario gestoßen, in dem es als schlecht angesehen wird.

PS: Ich denke, meine Frage ist ein bisschen naiv, aber sie nervt mich so sehr, dass ich danach fragen musste.


2
Lesen Sie Kimberly Tripps Blog-Beiträge zum Clustered-Index - sie ist die Königin der Indizierung in der SQL Server-Welt, und ihre grundlegende Empfehlung lautet immer, sie INT IDENTITYals Primärschlüssel (und Clustered-Schlüssel) für fast jede Tabelle zu verwenden. Es ist eine empfehlenswerte Best Practice und funktioniert normalerweise einwandfrei. Fälle, in denen dies keine gute Idee ist, sind meiner Meinung nach relativ selten.
marc_s

1
Ja, ich habe diese Blogs gelesen und seitdem ich diese Praxis befolgt habe. Aber ich wollte nur wissen, in welchen Fällen sie Probleme verursachen, wie unten erwähnt. :)
Kai

Antworten:


5

Normalerweise verwende ich eine Identitätsspalte als gruppierten Primärschlüssel. In einigen (seltenen?) Fällen ist dies jedoch aufgrund der LastPageInsertLatchContention nicht ideal. Dies geschieht, wenn eine Tabelle stark mit Daten gefüllt ist. Aufgrund des Identitätsschlüssels möchten alle diese INSERT's die letzte Seite der Tabelle (Index) schreiben. Diese Seite kann also gesperrt werden und die Leistung kann mit einer anderen Lösung besser sein.

Sehen

für Details.


1
Ich denke, "ist stark mit Daten gefüllt" sollte expliziter sein: "hat ein konstant hohes Volumen an Einfügungen" ist die direktere Ursache des Systems, nicht nur, dass die Tabelle groß ist.
Aaron Bertrand

Natürlich hast du recht. Dies ist nur dann der Fall, wenn viele Zeilen gleichzeitig eingefügt werden. Dies hängt nicht von der Größe der Tabelle ab.
Lothar Kraner

Ich habe also eine Tabelle, in die wir viele Daten (~ 100.000 Zeilen im TXT-Format) mithilfe der Masseneinfügung importieren. Ich denke in diesem Fall könnte ein Identitätsclusterindex ein Problem verursachen.
Kai

Es hängt davon ab, ob :). Erstens hängt es von der Last der Tabelle ab, die gleichzeitig von anderen Prozessen geladen wird. Dies hängt auch von der Größe Ihrer Zeilen ab (je mehr Zeilen auf einer einzelnen Seite von 8 KB ausgeführt werden, desto häufiger kann das Problem auftreten). Normalerweise ist das kein Problem. Ich fürchte, Sie müssen es testen, da dies normalerweise ein großes Problem darstellt. Vielleicht standen auch andere Menschen vor dem Problem.
Lothar Kraner

In 22 Jahren Arbeit mit SQL Server habe ich NIE einen Fall gesehen, in dem das, was Lothar behauptet, passiert ist. Ich habe an einem Projekt gearbeitet, bei dem GUIDs als Clustered-Indizes verwendet wurden und GUIDs dazu führten, dass die Datenbank zusammenbrach. Acht Jahre später lässt das langsame Computersystem Mörder frühzeitig dallasnews.com/news/crime/2016/08/25/… raus .
Duane Lawrence

6

Ich habe nie eine Identitätsspalte gesehen, die nicht auch ein Index ist, normalerweise der Primärschlüssel.

Jetzt müssen wir zwischen Primärschlüssel (PK) und Clustered Index (CI) unterscheiden. Der erste dreht sich um die Logik des Datenbankschemas, der Primärschlüssel unterscheidet eine Zeile von allen anderen in der Tabelle und der Fremdschlüssel für andere Tabellen. Eine Identitätsspalte ist immer ein Kandidatenschlüssel, aber sie ist künstlich und Sie möchten möglicherweise den natürlichen Kandidatenschlüssel als PK.

Beim Clustered Index geht es stattdessen darum, wie der Index aus den Daten erstellt und gespeichert wird. Es kann nur einen Clustered-Index geben, und dies ist der einzige Index, der auf die Daten in der Tabelle verweist. Alle anderen Indizes beziehen sich auf den Clustered-Index.

Normalerweise ist die PK auch das CI, aber das ist einfach das Standardverhalten. Ich habe PK gesehen und manchmal erstellt, die kein CI waren: Der PK war der natürliche Schlüssel, der CI war die Identitätsspalte. Um die Funktionsweise des Index zu vereinfachen, ist der Index umso schneller, je kleiner die Daten in der CI-Definition sind, und das CI muss so schnell wie möglich sein. In Fällen, in denen die PK sehr groß ist und eine Identitätsspalte wie die hat Wenn Sie den Clustered-Index und die PK zu einem Nicht-Clustering-Index machen, wird die Leistung verbessert.

Meiner Meinung nach ist die Verwendung einer Identitätsspalte als Clustered-Index keine schlechte Idee, aber das bedeutet nicht, dass sie auch der Primärschlüssel sein sollte.

Das einzige Szenario, in dem ich mir vorstellen kann, dass eine Identitätsspalte eine schlechte Wahl sein kann, ist, wenn so viele eingehende Daten vorhanden sind, dass selbst die Erstellung der Identität die Leistung beeinträchtigt.


5

Welche Schlüssel / Indizes zu gruppieren sind, ist keine exakte Wissenschaft. Die beste Verwendung eines Clustered-Index kann je nach Verwendung der Tabelle (und der Verwendung der Spalten in diesem Schlüssel) variieren.

Der Clustered Key ist effizienter für Abfragen, bei denen viele Zeilen in einem Bereich ausgewählt werden, da keine zusätzlichen Zeilensuchen erforderlich sind, um die Daten für die nach dem Durchsuchen des Index gefundenen Zeilen zu finden. Es hilft auch bei der Suche nach einzelnen Zeilen, aber der Unterschied ist nicht so deutlich. Zum Beispiel haben wir Tabellen, die häufig nach der Objektbesitzer-ID durchsucht werden (und nicht nach der Objekt-ID, die der Primärschlüssel ist). Daher ist es für unsere App effizienter, wenn der Index für diese Spalte der Cluster-Schlüssel ist, ähnlich wie es manchmal der Fall ist Es ist viel besser, den Clusterschlüssel in häufig referenzierten Datumsspalten zu haben, wenn häufig nach Zeilen über Datumsbereichen gesucht wird.

Wenn die PK einer bestimmten Tabelle häufig ein Verknüpfungsziel ist, kann das Clustering der PK hilfreich sein, da bei bestimmten Verknüpfungsvorgängen die Reduzierung weiterer Seitensuchen ein großer Bonus sein kann, und natürlich, wenn Sie eine PK haben, die auf realen Daten basiert (und nicht) Ein Ersatzschlüssel wie eine Auto-Inkrement-Nummer (UUID), der Fernabfragen unterliegt, bietet die erwarteten Vorteile. Diese Gründe sind der Grund, warum das Clustering Ihrer PK im Allgemeinen eine gute Ausgangsposition ist, bevor andere Überlegungen berücksichtigt werden, und daher eine häufige Empfehlung (und manchmal eine automatisch angewendete Standardeinstellung).

Als Randnotiz: Wenn Sie am Ende eine UUID-Spalte anstelle eines inkrementierenden Integer-Typs als PK in einer Tabelle verwenden, kann das Clustering darauf die Leistung beeinträchtigen, da die zusätzlichen Seitenaufteilungen durch Einfügen "zufälliger" Daten in den Index ( Jede im Clustered-Index geteilte Seite führt zu einer zusätzlichen E / A-Aktivität auch für alle anderen Indizes in der Tabelle. Dies verlangsamt Einfügungen und kann Fragmentierungsprobleme im Laufe der Zeit verschlimmern. In dieser Situation kann es daher oft viel besser sein, einen anderen Index zu gruppieren (oder manchmal überhaupt keinen Clustered-Index zu haben , obwohl dies unter SQL Server für Azure [1] nicht möglich ist und es selten vorkommt, dass kein Clustered-Schlüssel vorhanden ist insgesamt eher ein Vorteil als ein Nachteil).

[1] Es ist seit einiger Zeit möglich, einen Heap (eine Tabelle ohne Clustering-Schlüssel) in Azure SQL zu haben, obwohl ähnliche Einschränkungen wie in On-Pre-SQL Server selten eine gute Idee sind


3

Ich möchte einige Beispiele in realen Szenarien, in denen die Verwendung einer Identitätsspalte als Clustered-Index eine schlechte Idee ist.

Im Allgemeinen ist es eine schlechte Idee, wenn der Identitätsclusterindex einfach ein redundanter, zusätzlicher Index ist. Sie erhalten nur einen Clustered-Index. Wenn Sie also den falschen auswählen, werden alle Ihre Transaktionen kostenpflichtig.

Wenn Sie bereits einen zusammengesetzten Schlüssel oder einen natürlichen Schlüssel benötigen, ist es eine schlechte Idee, eine Identitätsspalte als Clustered-Index zu haben.

Zwei gängige Szenarien, in denen zusammengesetzte Schlüssel verwendet werden sollten, sind "Tabellen verknüpfen" und "verschachtelte Tabellen", z.

create table a(id int identity primary key)
create table b(id int identity primary key)
create table a_b
( 
  a_id int not null references a,
  b_id int not null references b,
  constraint pk_a_b primary key (a_id,b_id),
  constraint ak_a_b unique (b_id, a_id)
)

Das Hinzufügen eines Identitätsspalten-Clustered-Index ist nutzlos und schädlich.

Ein häufiges Beispiel für die zweite Tabelle sind "verschachtelte" Tabellen, bei denen nur eine einzige zusammengesetzte PK erforderlich ist:

create table a(id int identity primary key)
create table a_detail
(
  a_id int not null references a,
  id int not null identity, 
  constraint pk_a_detail primary key (a_id,id) 
)

Unumstrittene Anwendungsfälle für natürliche Schlüssel umfassen Nachschlagetabellen, z

create table region
(
  region_code char(3) not null primary key,
  name nvarchar(200),
  description nvarchar(200)
)

Etwas kontroverser, aber IMO-korrekt ist die Verwendung von sequentiellem UNIQUEIDENTIFIER als Cluster-PK. Dies ist auch ein Szenario, in dem das Hinzufügen einer IDENTITY-Spalte mit einem Clustered-Index schädlich ist.


0

Wenn Sie Detailtabellen implementieren und einen einspaltigen Primärschlüssel beibehalten möchten, sollten Sie Folgendes berücksichtigen:

CREATE TABLE Parent (
    Parent_ID int NOT NULL IDENTITY(1,1),
    Parent_Data varchar(100) NULL,
    CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED (Parent_ID)
);

CREATE TABLE Parent_Detail (
    Parent_Detail_ID int NOT NULL IDENTITY(1,1),
    Parent_ID int NOT NULL,
    Detail_Data varchar(100) NULL,
    CONSTRAINT PK_Parent_Detail PRIMARY KEY NONCLUSTERED (Parent_Detail_ID),
    INDEX CX_Parent_Detail UNIQUE CLUSTERED (Parent_ID, Parent_Detail_ID),
    CONSTRAINT FK_Parent_Detail_Parent FOREIGN KEY (Parent_ID) REFERENCES Parent (Parent_ID)
);

Ich habe die übergeordnete Tabelle mit einem gruppierten Primärschlüssel in der Identitätsspalte eingerichtet. Für die Parent_Detail-Tabelle ist die Identitätsspalte der Primärschlüssel, der Clustering-Index befindet sich jedoch auf dem Fremdschlüssel (Parent_ID), gefolgt von der Identitätsspalte. Indem wir die Identitätsspalte zum Clustering-Index hinzufügen (wie es David Browne in seiner Lösung getan hat) und dann den Clustering-Index als eindeutig definieren, vermeiden wir den 4-Byte-Eindeutiger. Obwohl der Uniquifier nur hinzugefügt wird, wenn dies für bestimmte Datensätze erforderlich ist ( https://sqlquantumleap.com/2017/09/18/clustered-index-uniquifier-existence-and-size/ hat eine gute Beschreibung), fühle ich mich besser Definieren meiner Cluster-Indizes für Nicht-Primärschlüssel mit UNIQUE, wenn möglich.

Durch Clustering mit der Spalte Parent_ID an der führenden Position aktivieren wir den Clustered-Index-Range-Scan zum Identifizieren von Detaildatensätzen für einen bestimmten übergeordneten Datensatz, wodurch die Leistung für diesen allgemeinen Anwendungsfall verbessert werden sollte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.