it-swarm-eu.dev

Leistungsunterschied zwischen Clustered und Non Clustered Index

Ich habe Clustered und Non Clustered Indexes Gelesen.

Clustered Index - Es enthält Datenseiten. Das bedeutet, dass die vollständigen Zeileninformationen in der Clustered Index Column vorhanden sind.

Non Clustered Index - Es enthält nur die Zeilenlokalisierungsinformationen in Form einer Spalte "Clustered Index" (falls verfügbar) oder der Datei-Indentifier + Seitenzahl + Gesamtzahl der Zeilen auf einer Seite. Dies bedeutet, dass die Abfrage-Engine einen zusätzlichen Schritt ausführen muss, um die tatsächlichen Daten zu lokalisieren.

Abfrage - Wie kann ich den Leistungsunterschied anhand eines praktischen Beispiels überprüfen, da wir wissen, dass die Tabelle nur einen Clustered Index Haben kann und sorting am Clustered Index Column Und Non Clustered Index Geben sorting nicht an und unterstützen 999 Non Clustered Indexes In SQL Server 2008 Und 249 in SQL Server 2005.

22
Pankaj Garg

Sehr gute Frage, da es sich um ein so wichtiges Konzept handelt. Dies ist jedoch ein großes Thema, und ich werde Ihnen eine Vereinfachung zeigen, damit Sie die Grundkonzepte verstehen können.

Erstens, wenn Sie Clustered Index sehen, denken Sie an Tabelle . Wenn eine Tabelle in SQL Server keinen Clustered-Index enthält, handelt es sich um einen Heap. Durch das Erstellen eines Clustered-Index für die Tabelle wird die Tabelle tatsächlich in eine Struktur vom Typ B-Tree umgewandelt. Ihr Clustered-Index IS Ihre Tabelle ist nicht von der Tabelle getrennt

Haben Sie sich jemals gefragt, warum Sie nur einen Clustered-Index haben können? Wenn wir zwei Clustered-Indizes hätten, würden wir zwei Kopien der Tabelle benötigen. Es enthält schließlich die Daten.

Ich werde versuchen, dies anhand eines einfachen Beispiels zu erklären.

HINWEIS: Ich habe die Tabelle in diesem Beispiel erstellt und mit über 3 Millionen zufälligen Einträgen gefüllt. Dann wurden die eigentlichen Abfragen ausgeführt und die Ausführungspläne hier eingefügt.

Was Sie wirklich verstehen müssen, ist O Notation oder Betriebseffizienz. Nehmen wir an, Sie haben die folgende Tabelle.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Hier haben wir also eine Basistabelle mit einem Clustered Key auf CustomerID (der Primärschlüssel ist standardmäßig geclustert). Somit wird die Tabelle basierend auf dem Primärschlüssel CustomerID angeordnet/geordnet. Die Zwischenstufen enthalten die CustomerID-Werte. Die Datenseiten enthalten die gesamte Zeile, es handelt sich also um die Tabellenzeile.

Wir werden auch einen nicht gruppierten Index für das Feld CustomerName erstellen. Der folgende Code wird es tun.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

In diesem Index finden Sie also auf den Datenseiten/Knoten auf Blattebene einen Zeiger auf die Zwischenebenen im Clustered-Index. Der Index ist um das Feld CustomerName angeordnet. Somit enthält die Zwischenebene die CustomerName-Werte und die Blattebene den Zeiger (diese Zeigerwerte sind tatsächlich die Primärschlüsselwerte oder die CustomerID-Spalte).

Richtig, wenn wir die folgende Abfrage ausführen:

SELECT * FROM Customer WHERE CustomerID = 1 

SQL wird den Clustered-Index wahrscheinlich über eine Suchoperation lesen. Eine Suchoperation ist eine binäre Suche, die viel effizienter ist als ein Scan, bei dem es sich um eine sequentielle Suche handelt. In unserem obigen Beispiel wird der Index gelesen und mithilfe einer binären Suche kann SQL die Daten entfernen, die nicht den von uns gesuchten Kriterien entsprechen. Siehe angehängten Screenshot für den Abfrageplan.

(enter image description here

Die Anzahl der Operationen oder O-Notation für die Suchoperation ist also wie folgt:

  1. Führen Sie eine binäre Suche im Clustered-Index durch, indem Sie den gesuchten Wert mit den Werten in der Zwischenebene vergleichen.
  2. Geben Sie die übereinstimmenden Werte zurück (denken Sie daran, dass der Clustered-Index alle Daten enthält und alle Spalten aus dem Index zurückgeben kann, da es sich um die Zeilendaten handelt.)

Es sind also zwei Operationen. Wenn wir jedoch die folgende Abfrage ausgeführt haben:

SELECT * FROM Customer WHERE CustomerName ='John'

SQL verwendet jetzt den nicht gruppierten Index für den Kundennamen, um die Suche durchzuführen. Da es sich jedoch um einen nicht gruppierten Index handelt, enthält er nicht alle Daten in der Zeile.

Daher führt SQL die Suche auf den Zwischenebenen durch, um die übereinstimmenden Datensätze zu finden, und führt dann eine Suche mit den zurückgegebenen Werten durch, um eine weitere Suche im Clustered-Index (auch als Tabelle bezeichnet) durchzuführen und die tatsächlichen Daten abzurufen. Das klingt verwirrend, ich weiß, aber lesen Sie weiter und alles wird klar.

Da unser nicht gruppierter Index nur das Feld CustomerName (die in den Zwischenknoten gespeicherten indizierten Feldwerte) und den Zeiger auf die Daten enthält, bei denen es sich um die CustomerID handelt, enthält der Index keine Aufzeichnung des CustomerSurname. Der CustomerSurname muss aus dem Clustered-Index oder der Cluster-Tabelle abgerufen werden.

Beim Ausführen dieser Abfrage erhalte ich folgenden Ausführungsplan:

(enter image description here

Im obigen Screenshot sind zwei wichtige Dinge zu beachten

  1. SQL sagt, ich habe einen fehlenden Index (der Text in grün). SQL schlägt vor, einen Index für CustomerName zu erstellen, der CustomerID und CustomerSurname enthält.
  2. Sie werden auch sehen, dass 99% der Zeit der Abfrage für die Suche nach Schlüsseln für den Primärschlüsselindex/Clustered-Index aufgewendet wird.

Warum schlägt SQL den Index für CustomerName erneut vor? Nun, da der Index nur die CustomerID enthält und der CustomerName SQL immer noch den CustomerSurname aus den Tabellen-/Clustered-Indizes finden muss.

Wenn wir den Index erstellen und die Spalte CustomerSurname in den Index aufnehmen, kann SQL die gesamte Abfrage erfüllen, indem nur der nicht gruppierte Index gelesen wird. Aus diesem Grund schlägt SQL vor, meinen nicht gruppierten Index zu ändern.

Hier sehen Sie die zusätzliche Operation, die SQL ausführen muss, um die Spalte CustomerSurname aus dem Clustered Key abzurufen

Somit ist die Anzahl der Operationen wie folgt:

  1. Führen Sie eine binäre Suche für einen nicht gruppierten Index durch, indem Sie den gesuchten Wert mit den Werten in der Zwischenebene vergleichen
  2. Lesen Sie für übereinstimmende Knoten den Knoten auf Blattebene, der den Zeiger für die Daten im Clustered-Index enthält (die Knoten auf Blattebene enthalten übrigens die Primärschlüsselwerte).
  3. Lesen Sie für jeden zurückgegebenen Wert den Clustered-Index (die Tabelle), um die hier angegebenen Zeilenwerte zu erhalten. Wir lesen dann den CustomerSurname.
  4. Geben Sie übereinstimmende Zeilen zurück

Das sind 4 Operationen, um die Werte herauszuholen. Im Vergleich zum Lesen des Clustered-Index sind doppelt so viele Vorgänge erforderlich. Das zeigt Ihnen, dass Ihr Clustered-Index Ihr leistungsstärkster Index ist, da er alle Daten enthält.

Also nur um einen letzten Punkt zu verdeutlichen. Warum sage ich, dass der Zeiger im nicht gruppierten Index der Primärschlüsselwert ist? Um zu demonstrieren, dass die Knoten auf Blattebene des nicht gruppierten Index den Primärschlüsselwert enthalten, ändere ich meine Abfrage in:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

In dieser Abfrage kann SQL die CustomerID aus dem nicht gruppierten Index lesen. Der Clustered-Index muss nicht nachgeschlagen werden. Dies können Sie dem Ausführungsplan entnehmen, der so aussieht.

enter image description here

Beachten Sie den Unterschied zwischen dieser Abfrage und der vorherigen Abfrage. Es gibt keine Suche. SQL kann alle Daten im nicht gruppierten Index finden

Hoffentlich können Sie verstehen, dass der Clustered-Index die Tabelle ist und nicht-Clustered-Indizes NICHT alle Daten enthalten. Durch die Indizierung wird die Auswahl beschleunigt, da binäre Suchvorgänge durchgeführt werden können, aber nur Clustered-Indizes alle Daten enthalten. Eine Suche in einem nicht gruppierten Index führt daher fast immer dazu, dass Werte aus dem gruppierten Index geladen werden. Diese zusätzlichen Vorgänge machen nicht gruppierte Indizes weniger effizient als einen gruppierten Index.

Hoffe das klärt die Dinge auf. Wenn etwas keinen Sinn ergibt, schreibe bitte einen Kommentar und ich werde versuchen zu klären. Es ist ziemlich spät hier und mein Gehirn fühlt sich ein bisschen flach an. Zeit für einen roten Stier.

43
Namphibian

"Dies bedeutet, dass die Abfrage-Engine einen zusätzlichen Schritt ausführen muss, um die tatsächlichen Daten zu lokalisieren."

Nicht unbedingt - wenn der Index eine bestimmte Abfrage abdeckt, muss keine Reise zu den Datenseiten unternommen werden. Mit den enthaltenen Spalten können einem nicht gruppierten Index zusätzliche Spalten hinzugefügt werden, um ihn abzudecken, ohne die Schlüsselgröße zu ändern.

Die ultimative Antwort lautet also: Es hängt davon ab (von viel mehr Informationen, als Sie wirklich in einer einzigen Frage behandeln können). Sie müssen alle Funktionen der Indizes verstehen, und der Ausführungsplan für eine bestimmte Abfrage kann von Ihren Erwartungen abweichen.

Eine allgemeine Faustregel lautet, dass eine Tabelle immer einen Clustered-Index hat (und normalerweise eine Identität oder eine sequentielle GUID), aber aus Gründen der Leistung nicht-Clustered-Indizes hinzugefügt werden. Es gibt jedoch immer Ausnahmen - Heap-Tabellen haben einen Platz, breitere Clustered-Indizes haben einen Platz. Scheinbar redundante Indizes, die schmaler sind, um mehr Zeilen pro Seite aufzunehmen, haben einen Platz. usw. usw.

Und ich würde mir keine Sorgen über die Grenzen der verschiedenen zulässigen Indizes machen - das wird in vielen Beispielen aus der Praxis mit ziemlicher Sicherheit nicht zum Tragen kommen.

9
Cade Roux