In SQL Server sind zeilenorientierte Indizes, sowohl geclusterte als auch nicht geclusterte Indizes, als B-Bäume organisiert.
( Bildquelle )
Der Hauptunterschied zwischen geclusterten Indizes und nicht geclusterten Indizes besteht darin, dass die Blattebene des geclusterten Indexes ist den Tisch. Dies hat zwei Auswirkungen.
- Die Zeilen auf den Blattseiten des geclusterten Index enthalten immer etwas für jede der (nicht-dichten) Spalten in der Tabelle (entweder den Wert oder einen Zeiger auf den tatsächlichen Wert).
- Der geclusterte Index ist die primäre Kopie einer Tabelle.
Nicht geclusterte Indizes können auch Punkt 1 erfüllen, indem sie die INCLUDE
Klausel (seit SQL Server 2005), um explizit alle Nicht-Schlüsselspalten einzuschließen, aber sie sind 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. Die Indexseiten der oberen Ebene enthalten Werte für die Schlüsselspalten A, B
und die Seiten der Blattebene mit A, B, C, D
Es kann nur einen geclusterten Index pro Tabelle geben, da die Datenzeilen selbst nur in einer Reihenfolge sortiert werden können.
Das obige Zitat aus den SQL Server-Büchern im Internet sorgt für viel Verwirrung
Meiner Meinung nach wäre es viel besser, es so zu formulieren.
Es kann nur einen geclusterten Index pro Tabelle geben, da die Blattebenen-Zeilen des geclusterten Indexes sind die Tabellenzeilen.
Das Online-Zitat des Buches ist nicht falsch, aber Sie sollten sich darüber im Klaren sein, dass die "Sortierung" sowohl von nicht geclusterten als auch von geclusterten 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 weit verbreitete Annahme, dass bei einem geclusterten Index die Zeilen physisch immer in der gleichen Reihenfolge wie der Index auf der Platte gespeichert werden Schlüssel falsch ist.
Dies wäre eine absurde Umsetzung. Wenn zum Beispiel eine Zeile in der Mitte einer 4-GB-Tabelle eingefügt wird, macht SQL Server no 2 GB an Daten in der Datei nach oben kopieren müssen, um Platz für die neu eingefügte Zeile zu schaffen.
Stattdessen erfolgt eine Seitenteilung. Jede Seite auf der Blattebene sowohl von geclusterten als auch von nicht geclusterten Indizes hat die Adresse ( File: Page
) der nächsten und vorherigen Seite in logischer Reihenfolge der Schlüssel. Diese Seiten müssen weder zusammenhängend noch in Schlüsselreihenfolge sein.
Die verlinkte Seitenkette könnte z.B. lauten 1:2000 <-> 1:157 <-> 1:7053
Bei einer Seitenteilung wird eine neue Seite von einer beliebigen Stelle in der Dateigruppe aus zugewiesen (entweder von einem gemischten Extent für kleine Tabellen oder einem nicht leeren einheitlichen Extent, der zu diesem Objekt gehört, oder einem neu zugewiesenen einheitlichen Extent). Wenn die Dateigruppe mehr als eine Datei enthält, muß diese nicht einmal in derselben Datei liegen.
Das Ausmaß, in dem die logische Reihenfolge und die Kontiguität von der idealisierten physischen Version abweichen, ist der Grad der logischen Fragmentierung.
In einer neu erstellten Datenbank mit einer einzigen 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
Überprüfen Sie dann 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 durchwachsen. Die erste Zeile in der Reihenfolge der Schlüssel (mit Wert 1 - unten mit einem Pfeil hervorgehoben) befand sich fast auf der letzten physischen Seite.
Die Fragmentierung kann reduziert oder beseitigt werden, indem ein Index neu aufgebaut oder reorganisiert wird, um die Korrelation zwischen logischer Reihenfolge und physischer Reihenfolge zu erhöhen.
Nach der Ausführung
ALTER INDEX ix ON T REBUILD;
Ich habe folgendes erhalten
Wenn die Tabelle keinen geclusterten Index hat, wird sie als Heap bezeichnet.
Nicht geclusterte Indizes können entweder auf einem Heap oder einem geclusterten Index aufgebaut werden. Sie enthalten immer einen Zeilenlokator zurück zur Basistabelle. Im Falle eines Heaps ist dies ein physischer Zeilenbezeichner (rid) und besteht aus drei Komponenten (Datei:Seite: Slot). Im Falle eines Clustered Index ist der Zeilenlokator logisch (der Schlüssel des Clustered Index).
Im letzteren Fall, wenn der nicht geclusterte Index die CI-Schlüsselspalte(n) entweder als NCI-Schlüsselspalten oder INCLUDE
-d Spalten, dann wird nichts hinzugefügt. Andernfalls wird die fehlende(n) CI-Schlüsselspalte(n) stillschweigend zur NCI hinzugefügt.
SQL Server stellt immer sicher, dass die Schlüsselspalten für beide Arten von Indizes eindeutig sind. Der Mechanismus, mit dem dies für nicht als eindeutig deklarierte Indizes erzwungen wird, unterscheidet sich jedoch zwischen den beiden Indextypen.
Geclusterte Indizes erhalten eine uniquifier
für alle Zeilen mit Schlüsselwerten, die eine bestehende Zeile duplizieren, hinzugefügt. Dies ist nur eine aufsteigende Ganzzahl.
Bei nicht geclusterten Indizes, die nicht als eindeutig deklariert sind, fügt SQL Server den Zeilenlokator stillschweigend in den nicht geclusterten Indexschlüssel ein. Dies gilt für alle Zeilen, nicht nur für die, die tatsächlich Duplikate sind.
Die Nomenklatur "geclustert" vs. "nicht geclustert" wird auch für Indizes von Spaltenspeichern verwendet. Das Papier Erweiterungen für SQL Server-Spaltenspeicher Staaten
Obwohl die Daten des Spaltenspeichers nicht wirklich nach einem Schlüssel "geclustert" sind, haben wir haben wir uns entschieden, die traditionelle SQL Server-Konvention beizubehalten und den den Primärindex als Cluster-Index zu bezeichnen.