In zeilenorientiertem SQL Server-Speicher sind sowohl Clustered- als auch Nonclustered-Indizes als B-Bäume organisiert.
( Bildquelle )
Der wesentliche Unterschied zwischen Clustered - Indizes und nicht gruppiert Indizes ist , dass die Blattebene des gruppierten Index ist die Tabelle. Dies hat zwei Auswirkungen.
- Die Zeilen auf den gruppierten Indexblattseiten enthalten immer etwas für jede der (nicht spärlichen) Spalten in der Tabelle (entweder den Wert oder einen Zeiger auf den tatsächlichen Wert).
- Der Clustered-Index ist die primäre Kopie einer Tabelle.
Nicht geclusterte Indizes können auch Punkt 1 ausführen, indem sie die INCLUDE
Klausel (Seit SQL Server 2005) verwenden, um alle Nichtschlüsselspalten explizit einzuschließen. Es handelt sich jedoch um sekundäre Darstellungen, und es gibt immer eine weitere Kopie der Daten (die Tabelle selbst).
CREATE TABLE T
(
A INT,
B INT,
C INT,
D INT
)
CREATE UNIQUE CLUSTERED INDEX ci ON T(A,B)
CREATE UNIQUE NONCLUSTERED INDEX nci ON T(A,B) INCLUDE (C,D)
Die beiden obigen Indizes sind nahezu identisch. Mit den Indexseiten der oberen Ebene, die Werte für die Schlüsselspalten enthalten, A,B
und den Seiten auf Blattebene, die Werte enthaltenA,B,C,D
Es kann nur einen Clustered-Index pro Tabelle geben, da die Datenzeilen selbst nur in einer Reihenfolge sortiert werden können.
Das obige Zitat aus den Online-Büchern von SQL Server sorgt für große Verwirrung
Meiner Meinung nach wäre es viel besser formuliert als.
Es kann nur ein Clustered - Index pro Tabelle, weil die Blattebene Reihen des Clustered - Index sind die Tabellenzeilen.
Das Online-Zitat der Bücher ist nicht falsch, aber Sie sollten sich darüber im Klaren sein, dass die "Sortierung" sowohl von nicht gruppierten als auch von gruppierten Indizes logisch und nicht physisch ist. Wenn Sie die Seiten auf Blattebene lesen, indem Sie der verknüpften Liste folgen und die Zeilen auf der Seite in Slot-Array-Reihenfolge lesen, lesen Sie die Indexzeilen in sortierter Reihenfolge, aber physisch sind die Seiten möglicherweise nicht sortiert. Die gemeinsame Überzeugung , dass mit einem Clustered - Index der Zeilen immer physikalisch auf der Festplatte in der gleichen Reihenfolge wie der Index gespeichert Schlüssel ist falsch.
Dies wäre eine absurde Implementierung. Zum Beispiel , wenn eine Zeile in die Mitte einer 4 GB - Tabelle eingefügt wird SQL Server ist nicht hat 2 GB an Daten in der Datei , um Platz für die neu eingefügte Zeile zu kopieren.
Stattdessen erfolgt eine Seitenteilung. Jede Seite auf Blattebene sowohl von gruppierten als auch von nicht gruppierten Indizes hat die Adresse ( File:Page
) der nächsten und vorherigen Seite in logischer Schlüsselreihenfolge. Diese Seiten müssen weder zusammenhängend noch in Schlüsselreihenfolge sein.
zB könnte die verknüpfte Seitenkette sein 1:2000 <-> 1:157 <-> 1:7053
Wenn ein Seitenteilung erfolgt, wird eine neue Seite von einer beliebigen Stelle in der Dateigruppe zugewiesen (entweder von einer gemischten Ausdehnung für kleine Tabellen oder einer nicht leeren einheitlichen Ausdehnung, die zu diesem Objekt gehört, oder einer neu zugewiesenen einheitlichen Ausdehnung). Dies befindet sich möglicherweise nicht einmal in derselben Datei, wenn die Dateigruppe mehr als eine enthält.
Der Grad, in dem sich die logische Reihenfolge und Kontiguität von der idealisierten physischen Version unterscheidet, ist der Grad der logischen Fragmentierung.
In einer neu erstellten Datenbank mit einer einzelnen Datei habe ich Folgendes ausgeführt.
CREATE TABLE T
(
X TINYINT NOT NULL,
Y CHAR(3000) NULL
);
CREATE CLUSTERED INDEX ix
ON T(X);
GO
--Insert 100 rows with values 1 - 100 in random order
DECLARE @C1 AS CURSOR,
@X AS INT
SET @C1 = CURSOR FAST_FORWARD
FOR SELECT number
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 100
ORDER BY CRYPT_GEN_RANDOM(4)
OPEN @C1;
FETCH NEXT FROM @C1 INTO @X;
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO T (X)
VALUES (@X);
FETCH NEXT FROM @C1 INTO @X;
END
Dann überprüfte das Seitenlayout mit
SELECT page_id,
X,
geometry::Point(page_id, X, 0).STBuffer(1)
FROM T
CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
ORDER BY page_id
Die Ergebnisse waren überall. Die erste Zeile in Schlüsselreihenfolge (mit dem Wert 1 - hervorgehoben durch den Pfeil unten) befand sich fast auf der letzten physischen Seite.
Die Fragmentierung kann reduziert oder entfernt werden, indem ein Index neu erstellt oder organisiert wird, um die Korrelation zwischen logischer und physischer Reihenfolge zu erhöhen.
Nach dem Rennen
ALTER INDEX ix ON T REBUILD;
Ich habe folgendes
Wenn die Tabelle keinen Clustered-Index hat, wird sie als Heap bezeichnet.
Nicht gruppierte Indizes können entweder auf einem Heap- oder einem gruppierten Index erstellt werden. Sie enthalten immer einen Zeilenlokator zurück zur Basistabelle. Im Fall eines Heaps ist dies eine physische Zeilenkennung (rid) und besteht aus drei Komponenten (Datei: Seite: Steckplatz). Bei einem Clustered-Index ist der Zeilenlokator logisch (der Clustered-Indexschlüssel).
Für den letzteren Fall wird INCLUDE
nichts hinzugefügt, wenn der nicht gruppierte Index die CI-Schlüsselspalte (n) entweder als NCI-Schlüsselspalten oder als -d-Spalten enthält. Andernfalls werden die fehlenden CI-Schlüsselspalten stillschweigend zur NCI hinzugefügt.
SQL Server stellt immer sicher, dass die Schlüsselspalten für beide Indextypen eindeutig sind. Der Mechanismus, mit dem dies für nicht als eindeutig deklarierte Indizes erzwungen wird, unterscheidet sich jedoch zwischen den beiden Indextypen.
Clustered-Indizes werden uniquifier
für alle Zeilen mit Schlüsselwerten hinzugefügt, die eine vorhandene Zeile duplizieren. Dies ist nur eine aufsteigende Ganzzahl.
Bei nicht gruppierten Indizes, die nicht als eindeutig deklariert sind, fügt SQL Server den Zeilen-Locator stillschweigend dem nicht gruppierten Indexschlüssel hinzu. Dies gilt für alle Zeilen, nicht nur für diejenigen, die tatsächlich Duplikate sind.
Die Nomenklatur "Clustered vs Nonclustered" wird auch für Spaltenspeicherindizes verwendet. Die Papiere Erweiterungen SQL Server Column Stores Staaten
Obwohl die Spaltenspeicherdaten auf keinem Schlüssel wirklich "geclustert" sind, haben wir uns entschlossen, die traditionelle SQL Server-Konvention beizubehalten, den Primärindex als Clustered-Index zu bezeichnen.