Sollte der Index für eine Identitätsspalte nicht gruppiert sein?


19

Soll für eine Tabelle mit Identitätsspalte ein gruppierter oder nicht gruppierter PK / eindeutiger Index für die Identitätsspalte erstellt werden?

Der Grund ist, dass andere Indizes für Abfragen erstellt werden. Eine Abfrage, die einen nicht gruppierten Index (auf einem Heap) verwendet und Spalten zurückgibt, die nicht vom Index abgedeckt werden, verwendet weniger logische E / A (LIO), da keine zusätzlichen Suchschritte für den gruppierten Index-B-Tree vorhanden sind.

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

Clustered PK in Identitätsspalte ist gut, weil:

  1. Sie nimmt eintönig zu, sodass beim Einfügen keine Seitenteile auftreten. Es heißt, eine Masseneinfügung kann so schnell sein wie auf einem Heap-Tisch (nicht gruppiert)

  2. Es ist eng

Werden die Abfragen in der Frage jedoch schneller sein, ohne dass sie gruppiert werden?

** Update: ** Was ist, wenn die IdFK von anderen Tabellen ist und es in einigen Abfragen verbunden wird?


3
Es ist nicht besser oder schlechter, es kommt darauf an.
Aaron Bertrand

1
@ypercube Der Link kejser.org/clustered-indexes-vs-heaps sagte, dass das Nicht-CI weniger LIO haben wird.
U23432534

2
Ich habe den Artikel in der Vergangenheit gelesen und es zeigt sicherlich, dass es Fälle für einen Clustered-Index und Fälle für einen Haufen gibt. Es ist nicht alles schwarz oder alles weiß.
ypercubeᵀᴹ

4
Ich bin mir nicht sicher, ob Ihre Antwort auf @ypercube einem der von Herrn Kejser genannten Kriterien entspricht - zumindest mit den von Ihnen mitgeteilten Details. In der jetzigen Form bin ich mir nicht sicher, ob dies eine nützliche Antwort liefern wird, da es fast jedes einzelne Szenario abdecken müsste - was bereits in dem von Ihnen zitierten Blog-Beitrag geschehen ist. Wenn Sie weitere Details zu Ihrem speziellen Szenario bereitstellen können, kann möglicherweise ein Teil des Wissens in der Veröffentlichung angewendet werden.
Swasheck

2
Es wird von Dingen abhängen wie: a) Workload (OLTP? OLAP? Etc?), B) Tabellengröße (n), c) Normalform, um nur einige zu nennen. Sie haben keine Details zu einem dieser Faktoren angegeben, sodass Empfehlungen auf Vermutungen aus Ihrer Umgebung beruhen. Haben Sie auch versucht, die von Ihnen vorgeschlagenen Abfragen (mit gelöschten Puffern) zu profilieren und die spezifischen E / A-Profile pro Konfiguration abzurufen, um sich selbst davon zu überzeugen?
Swasheck

Antworten:


16

Standardmäßig ist die PK geclustert und dies ist in den meisten Fällen in Ordnung. Welche Frage sollte jedoch gestellt werden:

  • sollte meine PK geclustert werden?
  • Welche Spalte (n) sind der beste Schlüssel für meinen Clustered-Index?

PK und Clustered Index sind zwei Unterschiede:

  • PK ist eine Einschränkung. PK wird verwendet, um Zeilen eindeutig zu identifizieren, es gibt jedoch keine Vorstellung von Speicherung. Standardmäßig (in SSMS) wird dies jedoch durch einen eindeutigen Clustered-Index erzwungen, wenn noch kein Clustered-Index vorhanden ist.
  • Clustered-Indizes sind ein spezieller Indextyp, in dem Zeilendaten auf Blattebene gespeichert werden, dh, sie decken immer ab. Alle Spalten, unabhängig davon, ob sie Teil des Schlüssels sind oder nicht, werden auf Blattebene gespeichert. Es muss nicht eindeutig sein. In diesem Fall wird dem gruppierten Schlüssel ein Eindeutiger (4 Byte) hinzugefügt.

Jetzt haben wir zwei Fragen:

  • Wie möchte ich Zeilen in meiner Tabelle (PK) eindeutig identifizieren?
  • Wie möchte ich es auf der Blattebene eines Index speichern (Clustered Index)

Es kommt darauf an, wie:

  • Sie entwerfen Ihr Datenmodell
  • Sie fragen Ihre Daten ab und Sie schreiben Ihre Abfragen
  • Sie fügen Ihre Daten ein oder aktualisieren sie
  • ...

Benötigen Sie zunächst einen Clustered-Index? Wenn Sie eine Masseneinfügung durchführen, ist es effizienter, ungeordnete Daten in einem HEAP zu speichern (im Vergleich zu geordneten Daten in einem Cluster). Es verwendet RID (Row Identifier, 8 Bytes), um Zeilen eindeutig zu identifizieren und auf Seiten zu speichern.

Der Clustered-Index sollte kein zufälliger Wert sein. Die Daten auf Blattebene werden gespeichert und nach dem Indexschlüssel sortiert. Daher sollte es kontinuierlich wachsen, um Fragmentierung oder Seitenteilung zu vermeiden. Wenn dies von der PK nicht erreicht werden kann, sollten Sie einen anderen Schlüssel als Clustered Candidate betrachten. Ein gruppierter Index für Identitätsspalten, eine sequenzielle GUID oder sogar das Datum der Einfügung ist aus sequenzieller Sicht in Ordnung, da alle Zeilen der letzten Blattseite hinzugefügt werden. Auf der anderen Seite sollten eindeutige Bezeichner, die für Ihre geschäftlichen Anforderungen als PK nützlich sein können, nicht zu Clustern zusammengefasst werden (sie werden nach dem Zufallsprinzip sortiert / generiert).

Wenn Sie nach einigen Daten- und Abfrageanalysen feststellen, dass Sie zum Abrufen Ihrer Daten meistens denselben Index verwenden, bevor Sie eine Schlüsselsuche in der Cluster-PK durchführen, können Sie ihn als Cluster-Index betrachten, obwohl er Ihre Daten möglicherweise nicht eindeutig identifiziert.

Der gruppierte Indexschlüssel besteht aus allen Spalten, die Sie indizieren möchten. Eine eindeutigere Spalte (4 Byte) wird hinzugefügt, wenn keine eindeutige Einschränkung vorliegt (inkrementeller Wert für Duplikate, andernfalls null). Dieser Indexschlüssel wird dann einmal für jede Zeile auf Blattebene aller nicht gruppierten Indizes gespeichert. Einige von ihnen werden auch mehrmals in Zwischenebenen (Verzweigungen) zwischen der Wurzel- und der Blattebene des Indexbaums (B-Baum) gespeichert. Wenn der Schlüssel zu groß ist, wird der gesamte nicht gruppierte Index größer, benötigt mehr Speicher und mehr E / A, CPU, Speicher, ... Wenn Sie einen PK für Name + Geburtsdatum + Land haben, ist es sehr wahrscheinlich, dass dieser Schlüssel vorhanden ist ist kein guter Kandidat. Es ist zu groß für einen Clustered-Index. Eindeutiger Bezeichner, der NEWSEQUENTIALID () verwendet, wird normalerweise nicht als schmaler Schlüssel (16 Byte) betrachtet, obwohl er sequentiell ist.

Sobald Sie herausgefunden haben, wie Sie Zeilen in Ihrer Tabelle eindeutig identifizieren können, können Sie eine PK hinzufügen. Wenn Sie glauben, dass Sie es in Ihrer Abfrage nicht verwenden werden, erstellen Sie es nicht in Clustern. Sie können immer noch einen anderen nicht gruppierten Index erstellen, wenn Sie ihn irgendwann abfragen müssen. Beachten Sie, dass der PK automatisch einen eindeutigen Index erstellt.

Die nicht gruppierten Indizes enthalten immer den gruppierten Schlüssel. Wenn sich jedoch die indizierten Spalten (+ Schlüsselspalten) decken, wird im Clustered-Index keine Schlüsselsuche durchgeführt. Vergessen Sie nicht, dass Sie einem nicht gruppierten Index auch Include und Where hinzufügen können. (Benutze es weise)

Der Clustered-Index sollte eindeutig und so eng wie möglich sein. Der Clustered-Index sollte sich im Laufe der Zeit nicht ändern und inkrementell eingefügt werden.

Es ist jetzt an der Zeit, SQL zu schreiben, mit dem die Indizes und Einschränkungen für Tabellen, Clustered und Nonclustered erstellt werden.

Dies ist alles theoretisch, da wir Ihr Datenmodell und die verwendeten Datentypen (A und B) nicht kennen.


11

Für eine Tabelle mit einem Primärschlüssel (PK) in einer Identitätsspalte wird diese standardmäßig geclustert. Könnte es besser sein als nicht gruppiert?

Wenn Sie gefragt werden, ob die Standardeinstellung für einen Primärschlüssel in einer Identitätsspalte (insbesondere) nicht gruppiert sein soll, würde ich Nein sagen. Die meisten Tabellen profitieren von einem Clustered-Index. Daher ist es wahrscheinlich insgesamt hilfreich, Clustered als Standard für eine Primärschlüsseleinschränkung festzulegen, insbesondere für neue Benutzer von SQL Server.

Wie bei so ziemlich jeder Option gibt es immer andere Umstände, unter denen einer dem anderen vorzuziehen ist, aber ein erfahrener DBA sollte den Standard kennen und in der Lage sein, ihn bei Bedarf außer Kraft zu setzen. Lesen Sie auch die entsprechenden Fragen und Antworten. Wann sollte ein Primärschlüssel als nicht gruppiert deklariert werden? .

Werden die Abfragen in der Frage schneller sein, ohne dass sie gruppiert werden?

Ja, aber mit Einschränkungen.

RID-Suchvorgänge sind in der Tat effizienter als Schlüsselsuchvorgänge. Selbst wenn sich alle erforderlichen Seiten im Arbeitsspeicher befinden (sehr wahrscheinlich für die oberen Ebenen eines Index), entstehen CPU-Kosten beim Navigieren im gruppierten Index-B-Tree. Infolgedessen kann SQL Server in der Regel viel mehr RID-Suchvorgänge als Schlüsselsuchvorgänge pro CPU-Zeiteinheit ausführen.

Vorbehalte

Das Obige ist oft kein entscheidender Faktor für die Entscheidung, ob eine Tabelle als Heap strukturiert werden soll oder nicht. Es müsste unpraktisch sein, Suchvorgänge (unter Verwendung von Deckungsindizes) zu vermeiden, und die Anzahl der Suchvorgänge müsste groß genug sein, um eine messbare (und wichtige) Auswirkung auf die Leistung in Anbetracht der Hardwareumgebung und der Arbeitslast zu haben.

Es ist nicht wirklich praktisch, in dieser Antwort alle Aspekte der Debatte zwischen Heap und Clustered-Index abzudecken, aber ich möchte sagen, dass es relativ wenige gute Gründe gibt, eine Tabelle generell als Heap zu strukturieren. Für mich würde die Auswahl des in der Frage vorgeschlagenen Designs eine sehr sorgfältige Analyse vor der Implementierung erfordern und eine hohe Messlatte erfüllen müssen. Allgemeine Argumente zur „Skalierbarkeit“ würden nicht ausreichen.

In Bezug auf die Aktualisierung der Frage zu Verknüpfungen wäre es Teil der oben genannten Analyse, die Auswirkungen des Verlusts des Clustered-Index auf Ausführungspläne zu bewerten. Wenn Joins mit verschachtelten Schleifen verwendet werden, ist es sehr praktisch, den Clustered-Index auf dem Join-Schlüssel zu haben, da alle Spalten der Zeile sofort ohne Lookup verfügbar sind.

Nach meiner eigenen Erfahrung ist es sehr oft von Vorteil, eindeutige Clustered-Indizes für Identitätsspalten zu haben. Ich habe Heaps in Bezug auf die Speicherverwaltung als problematisch empfunden, und ich sollte auch erwähnen, dass für einige SQL Server-Features ein eindeutiger Clustered-Index erforderlich ist, um zu funktionieren.


8

Tatsächlich müssen weder ein Clustered-Index noch ein Primärschlüssel erstellt werden, da eindeutige Indizes und nicht eindeutige Indizes die Arbeit erledigen können. SQL Server unterstützt seit mindestens Version 1.1 einen Clustered Index, der Primärschlüssel war jedoch nur ein "Konzept", das die Programmierer durch die Definition eines eindeutigen Index erzwangen.

Es scheint jedoch, dass sowohl Primärschlüssel als auch Clustered-Indizes in den meisten Datenbanken wertvolle Konzepte darstellen.

Sehen wir uns die SQL Server-Dokumentation an, um die Teilbeschreibungen einiger Indizierungsoptionen zu sehen, wie unten gezeigt.

Clustered Index: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • 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

Primärschlüssel: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Eine Tabelle kann nur eine PRIMARY KEY-Einschränkung enthalten.

  • Alle in einer PRIMARY KEY-Einschränkung definierten Spalten müssen als NOT NULL definiert sein.

  • Der Primärschlüssel kann als Clustered-Index (der Standardwert, wenn kein Clustered-Index vorhanden ist) oder als Non-Clustered-Index erstellt werden.

Eindeutiger Index: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Wenn Sie eine UNIQUE-Einschränkung erstellen, wird standardmäßig ein eindeutiger Nonclustered-Index erstellt, um eine UNIQUE-Einschränkung zu erzwingen.

  • Sie können einen UNIQUE Clustered Index angeben, wenn für die Tabelle noch kein Clustered Index vorhanden ist.

Dies bedeutet, dass Ihre Frage zu Clustered-Indizes und Primärschlüsseln einige der folgenden Punkte betrifft. Bitte beachten Sie, dass nicht jede Tabelle von demselben Indexierungsplan profitiert.

Wann würde ich davon profitieren, wenn der Primärschlüssel vom Clustered Index getrennt wäre?

Möglicherweise, wenn der gruppierte Index breit ist (z. B. 5 Spalten mit Textinformationen, aber der Primärschlüssel klein ist (INT oder BIGINT), wie Sie zu beschreiben scheinen.

  • Mit einem breiten Clustered-Index können Sie schnell Zeilen aus dem Index für eine Teilmenge von Abfragen auswählen, die serielle Antworten aus dem Clustered-Index (auch als Tabelle bezeichnet ) bereitstellen . Beispielsweise würde ein 5-Spalten-Clustered-Index das Scannen der Spalten C1, C2, C3, C4, C5 oder C1, C2, C3, C4 usw. bis hinunter zu C1 unterstützen.
  • Hinweis: Wenn die Zeilen groß sind, kann dies zu Geschwindigkeitsvorteilen bei der Auswahl der seriellen Zeilengruppe führen, insbesondere wenn andere Spalten in der Tabelle regelmäßig in der Ergebnismenge enthalten sind.
  • In diesem Fall können Sie den Primärschlüssel für die referenzielle Integrität verwenden, um den erforderlichen Wert als Fremdschlüssel bereitzustellen, um Zeilen in anderen Tabellen einzuschränken. Die PK ist klein und daher ist die FK ein kleiner Treffer für die Größe der referenzierten Tabelle (n).
  • Beachten Sie jedoch, dass jeder Index, der für eine Tabelle mit einem Clustered Index erstellt wird, alle Clusterspalten in den anderen Indizes enthält, die Sie für diese Tabelle erstellen. Ein breiter Clustered-Index würde die Größe aller nicht gruppierten Indizes für diese Tabelle erweitern.

Soll der Primärschlüssel allein zum Clustered-Index gemacht werden?

  • Wenn Sie einen kleinen Primärschlüssel (INT oder BIGINT) haben und es sich um den Clustered Index handelt, ist der Overhead der Clusterspalten relativ gering. Obwohl der geclusterte Primärschlüssel in diesem Fall auch in jedem Index dieser Tabelle vorhanden ist, ist der zu zahlende Preis geringer als bei dem oben diskutierten breiten Cluster.

  • Dieser Primärschlüssel-Clustered-Index bietet normalerweise keinen einfachen Weg zur seriellen Auswahl vieler Zeilen.

  • Was ist mit den anderen Spalten, die Sie einst in den Clustered-Index aufnehmen wollten, nachdem Sie einen Clustered-Primärschlüssel erstellt haben ?

  • Erstellen Sie nach Bedarf einen eindeutigen (oder einen nicht eindeutigen) Index, um diese umfassenden Suchkriterien der Spalten C1, C2, C3, C4, C5 zu indizieren. Die Werte in diesem "Imitation Clustered" -Index können als schnellerer Suchpfad für diese 5 Spalten dienen. Wenn es eine oder zwei nicht indizierte Spalten gibt, die ebenfalls regelmäßig ausgewählt werden, können sie mit in den Index aufgenommen werden INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Obwohl ich einfache Clustered-Indizes und Primärschlüssel für nützlich halte, gibt es einige gute Gründe, darüber nachzudenken, ob sie in einer Tabelle oder in einer Datenbank verwendet werden sollen.

Benötigen Sie überhaupt einen Clustered Index?

  • Wenn Sie Indizes erstellen (eindeutige Indizes und nicht eindeutige Indizes) und den Primärschlüssel definieren, ohne den Aufwand eines Clustered-Index zu verursachen, stellen Sie möglicherweise fest, dass die engeren Indizes Ihnen das bieten, was Sie für Ihre Abfragen benötigen.

  • Es gibt einige nützliche Verhaltensweisen in Clustered-Indizes und Primärschlüsseln, aber denken Sie daran, dass es wirklich die Indizes sind, die am wichtigsten sind. Entwerfen Sie die Indizierungsstrategie, um die Realitäten Ihrer Anwendung zu berücksichtigen. Möglicherweise OneBigTablemuss eine andere Indizierungsstrategie verwendet werden als für die meisten Tabellen.

  • Ohne einen Clustered Index werden Ihre Daten als Heap mit dem Row Identifier (RID) gespeichert, was überhaupt kein guter Suchmechanismus ist. Wie bereits erwähnt, können Sie jedoch eindeutige und nicht eindeutige Indizes erstellen, um Ihre Abfragen zu verarbeiten.

Nun kommen Sie zu Heaps:

Heaps und Indizes: https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • Wenn eine Tabelle als Heap gespeichert wird, werden einzelne Zeilen anhand eines Zeilenbezeichners (RID) identifiziert, der aus der Dateinummer, der Datenseitennummer und dem Steckplatz auf der Seite besteht. Die Zeilen-ID ist eine kleine und effiziente Struktur. (Aber es ist kein Index .)
  • Manchmal verwenden Datenarchitekten Heaps, wenn auf Daten immer über nicht gruppierte Indizes zugegriffen wird und die RID kleiner als ein gruppierter Indexschlüssel ist .

Wenn Sie jedoch auch einige "Hot Spots" in einem großen Datensatz haben, können Sie sich auch einen anderen Indextyp ansehen:

Gefilterter Index: https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • Ein gut gestalteter gefilterter Index verbessert die Abfrageleistung und die Qualität des Ausführungsplans, da er kleiner als ein nicht gruppierter Ganztabellenindex ist und gefilterte Statistiken enthält. Die gefilterten Statistiken sind genauer als die vollständigen Tabellenstatistiken, da sie nur die Zeilen im gefilterten Index abdecken .

  • Bei gefilterten Indizes gibt es eine Reihe von Einschränkungen, die im Link zu gefilterten Indizes aufgeführt sind.

Allerdings , wenn Sie im Denken über diese Möglichkeit des Überspringens von Primärschlüsseln und Clustered - Indizes insgesamt interessiert sind, können Sie Markus Winand der Post verbunden unten lesen. Mit einigen Codebeispielen demonstriert er seine Gründe dafür, dass es manchmal eine gute Idee sein könnte, auf die Verwendung dieser Funktionen zu verzichten.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Aber es kommt alles wieder darauf an, Ihre Anwendung zu verstehen und den Code, die Tabellen, die Indizes usw. so zu gestalten, dass sie zu dem Job passen, den Sie gerade ausführen.


Wenn ich in meiner täglichen Arbeit eine Tabelle finde, bei der es sich um einen Haufen handelt, halte ich dies für einen Fehler und erkundige mich bei den Entwicklern, ob es sich um einen absichtlichen Haufen handelt.
RLF

-2

Ein paar Punkte zu beachten.

Ein Index (gruppiert oder nicht) mit einem monoton ansteigenden Wert erspart Ihnen Seitenteile bei Masseneinfügungen, erstellt jedoch einen neuen Hotspot am hinteren Ende des Index. Auch wenn dies bei einer Masseneinfügung mit einem einzelnen Thread kein Problem darstellt, erhöht dies definitiv die Konkurrenz für eine Multithread-Anwendung, bei der neue Tupel mit einer hohen Rate eingefügt werden, da die Threads ständig um den Zugriff auf die letzte Seite des Index konkurrieren.

Das Clustering der Tabelle basierend auf einer Ersatz-PK (Identitäts-PK) ist selten vorteilhaft. Ein solcher Primärschlüssel wird meist verwendet, um entweder einzeln auf Tupel zuzugreifen oder den gesamten Index nach Joins zu durchsuchen. In beiden Fällen spielt es keine Rolle, ob der Index geclustert ist oder nicht (mit Ausnahme von Merge-Joins, kann es sein, aber wie häufig sind sie?)

Ich denke, dass Sie am meisten von einem Clustered-Index profitieren, der Abfragen abdeckt, die nach einem Schlüsselbereichsscan fragen, und zusätzliche Prädikate, die auf andere Spalten verweisen.


Wie hoch muss die Rate sein, damit dies tatsächlich zum Problem wird?
ypercubeᵀᴹ

@ypercube kann ich sagen "es kommt darauf an"? Weil es so ist. Wenn keine Trigger auf dem Tisch sind, würde ich erwarten, dass einige Konflikte mit einem Dutzend Threads auftreten, die insgesamt 1 KB-Einfügungen pro Sekunde umfassen.
Mustaccio


Ich bin nicht anderer Meinung, aber ich habe gefragt, wie weit man mit einem einzigen Hot Spot kommen kann. Ich erinnere mich, dass ich einen Artikel über das Einfügen von 30.000 Zeilen pro Sekunde in eine Tabelle mit IDENTITY als CI gesehen habe (wenn der Speicher mir gute Dienste leistet), aber ich kann den Blog-Beitrag nicht finden.
Ypercubeᵀᴹ

Diese Diskussion ist sinnlos, wenn keine konkrete Arbeitslast vorliegt, die gegen ein konkretes Schema auf einer bestimmten Hardware ausgeführt wird. Ich hoffe, wir können uns alle einig sein, dass ein Index für eine monoton ansteigende Sequenz einen "Hot Spot" schafft. Ob dies zu einem inakzeptablen Engpass führt und ob man sich darum kümmern sollte oder nicht, hängt von den Umständen ab.
Mustaccio
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.