SQL Server-Äquivalent zur Oracle USING INDEX-Klausel

9

Gibt es ein SQL Server 2008-Äquivalent zur USING INDEX-Klausel in Oracle? Speziell für das Konstrukt:

CREATE TABLE c(c1 INT, c2 INT);
CREATE INDEX ci ON c (c1, c2);
ALTER TABLE c ADD CONSTRAINT cpk PRIMARY KEY (c1) USING INDEX ci;

In der SQL Server- Dokumentation zu eindeutigen Indizes heißt es (Hervorhebung hinzugefügt):

Eindeutige Indizes werden auf folgende Weise implementiert:

PRIMARY KEY oder UNIQUE Einschränkung

Wenn Sie eine PRIMARY KEY-Einschränkung erstellen, wird automatisch ein eindeutiger Clustered-Index für die Spalte oder Spalten erstellt, wenn noch kein Clustered-Index für die Tabelle vorhanden ist und Sie keinen eindeutigen Nonclustered-Index angeben . Die Primärschlüsselspalte kann keine NULL-Werte zulassen.

Dies scheint zu implizieren, dass es eine Möglichkeit gibt, anzugeben, welcher Index für einen Primärschlüssel verwendet werden soll.

nik
quelle
Definieren Sie einfach die PK zusammen mit der Tabelle. create table c (c1 int not null primary key, c2 int)
a_horse_with_no_name
Es ist der Teil "Eine PK dazu bringen, einen benannten Index zu verwenden", an dem ich interessiert bin.
Nik
Nein, dazu gibt es keine Möglichkeit. Ein Primärschlüssel ist eine Einschränkung und ein Index. In dem, was Sie angegeben haben, ist der Primärschlüssel standardmäßig ein eindeutiger Clustered-Index. Dies würde den anderen definierten Index zu einem Duplikat machen, wenn Sie nicht sowohl c1 als auch c2 in die where-Klausel aufnehmen.
Aaron

Antworten:

7

Gibt es ein SQL Server 2008-Äquivalent zur USING INDEX-Klausel in Oracle?

Nein. Wenn Sie in SQL Server einen Primärschlüssel oder eine eindeutige Einschränkung erstellen, wird automatisch ein eindeutiger Index zur Unterstützung dieser Einschränkung mit denselben Schlüsseln erstellt.

Dies scheint zu implizieren, dass es eine Möglichkeit gibt, anzugeben, welcher Index für einen Primärschlüssel verwendet werden soll.

Nein. In der Dokumentation wird nur versucht zu erklären, ob der automatische unterstützende Index als gruppiert oder nicht gruppiert erstellt wird, wenn Sie dies nicht angeben. Es ist verwirrend formuliert, ich stimme zu.

Wenn Sie einer vorhandenen Tabelle eine Primärschlüsseleinschränkung hinzufügen, ohne eine Präferenz auszudrücken, wird der unterstützende Index zur Verdeutlichung geclustert, wenn in der Tabelle kein bereits vorhandener gruppierter Index vorhanden ist. Der unterstützende Index wird als nicht gruppiert erstellt, wenn bereits ein gruppierter Index vorhanden ist

Sie können einen gruppierten oder nicht gruppierten Primärschlüssel speziell anfordern, indem Sie: PRIMARY KEY CLUSTEREDoder PRIMARY KEY NONCLUSTERED.

Fairerweise ist die Dokumentation zu diesem Thema viel klarer:

table_constraint (Transact-SQL)

Paul White 9
quelle
5

Die SQL Server-Syntax zum Erstellen eines Clustered-Index, der auch ein Primärschlüssel ist, lautet:

CREATE TABLE dbo.c
(
    c1 INT NOT NULL, 
    c2 INT NOT NULL,
    CONSTRAINT PK_c
    PRIMARY KEY CLUSTERED (c1, c2)
);

Was Ihren Kommentar betrifft: "Eine PK einen benannten Index verwenden lassen", führt der obige Code dazu, dass der Primärschlüsselindex "PK_c" heißt.

Der Primärschlüssel und der Clusterschlüssel müssen nicht dieselben Spalten sein. Sie können sie separat definieren. Ändern Sie im obigen Beispiel das CLUSTEREDSchlüsselwort in NONCLUSTEREDund fügen Sie dann einfach einen Clustered-Index mit der folgenden CREATE INDEXSyntax hinzu:

CREATE TABLE dbo.c
(
    c1 INT,
    c2 INT,
    CONSTRAINT PK_c
    PRIMARY KEY NONCLUSTERED (c1, c2)
);

CREATE CLUSTERED INDEX CX_c ON dbo.c (c2);

In SQL Server der Clustered - Index ist der Tisch, sie sind ein-und-die-gleiche. Ein Clustered-Index definiert die logische Reihenfolge der in der Tabelle gespeicherten Zeilen. In meinem ersten Beispiel werden Zeilen in der Reihenfolge der Werte der Spalten c1und gespeichert c2. Da der Clustering-Schlüssel auch als Primärschlüssel definiert ist, muss die Kombination von c1und c2tabellenweit eindeutig sein.

Im zweiten Beispiel besteht der Primärschlüssel aus den Spalten c1und c2, der Clustering-Schlüssel ist jedoch nur die c2Spalte. Da ich das UNIQUEAttribut in der CREATE INDEXAnweisung nicht angegeben habe , muss der Clustering-Schlüssel ( c2) nicht in der gesamten Tabelle eindeutig sein. Ein "Eindeutiger" wird automatisch von SQL Server erstellt und an die Werte in der c2Spalte angehängt , um den Clustering-Schlüssel zu erstellen. Dieser Clustering-Schlüssel wird, da er jetzt eindeutig ist, als Zeilen-ID in anderen in der Tabelle erstellten Indizes verwendet.

Um zu beweisen, dass der Clustering-Schlüssel das Layout der im Speicher befindlichen Zeilen steuert, können Sie die undokumentierte Funktion verwenden fn_PhysLocCracker(%%PHYSLOC%%). Der folgende Code zeigt, dass die Zeilen in der Reihenfolge der c2Spalte, die ich als Clustering-Schlüssel definiert habe , auf der Festplatte angeordnet sind :

USE tempdb;

CREATE TABLE dbo.PKTest
(
    c1 INT NOT NULL
    , c2 INT NOT NULL
    , c3 VARCHAR(256) NOT NULL
);

ALTER TABLE PKTest 
ADD CONSTRAINT PK_PKTest 
PRIMARY KEY NONCLUSTERED (c1, c2);

CREATE CLUSTERED INDEX CX_PKTest 
ON dbo.PKTest(c2);

TRUNCATE TABLE dbo.PKTest;

INSERT INTO dbo.PKTest (c1, c2, c3)
SELECT TOP(25) o1.object_id / o2.object_id, o2.object_id, o1.name + '.' + o2.name
FROM sys.objects o1
    , sys.objects o2
WHERE o1.object_id >0 
    and o2.object_id > 0;

SELECT plc.file_id
    , plc.page_id
    , plc.slot_id
    , pk.*
FROM dbo.PKTest pk
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;

Die Ergebnisse meiner Tempdb sind:

Geben Sie hier die Bildbeschreibung ein

In der Abbildung oben werden die ersten drei Spalten von der fn_PhysLocCrackerFunktion ausgegeben und zeigen die physische Reihenfolge der Zeilen auf der Festplatte. Sie können sehen, dass der slot_idWert den Sperrschritt mit dem Wert erhöht c2, der der Clustering-Schlüssel ist. Der Primärschlüsselindex speichert Zeilen in einer anderen Reihenfolge. Dies lässt sich feststellen, indem SQL Server gezwungen wird, Ergebnisse vom Scannen des Primärschlüssels zurückzugeben:

SELECT pkt.c1
    , pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);

Beachten Sie, dass ich ORDER BYin der obigen Anweisung keine Klausel verwendet habe, da ich versuche, die Reihenfolge der Elemente im Primärschlüsselindex anzuzeigen.

Die Ausgabe der obigen Abfrage lautet:

Geben Sie hier die Bildbeschreibung ein

Wenn fn_PhysLocCrackerwir uns die Funktion ansehen, können wir die physikalische Reihenfolge des Primärschlüsselindex sehen.

SELECT plc.file_id
    , plc.page_id
    , plc.slot_id
    , pkt.c1
    , pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN)
CROSS APPLY fn_PhysLocCracker(%%PHYSLOC%%) plc;

Da wir ausschließlich aus dem Index selbst lesen, dh in der Abfrage keine Spalten außerhalb des Index referenziert werden, %%PHYSLOC%%repräsentieren die Werte die Seiten im Index selbst.

Die Ergebnisse:

Geben Sie hier die Bildbeschreibung ein

Max Vernon
quelle