La sintassi di SQL Server per la creazione di un indice cluster che è anche una chiave primaria è:
CREATE TABLE dbo.c
(
c1 INT NOT NULL,
c2 INT NOT NULL,
CONSTRAINT PK_c
PRIMARY KEY CLUSTERED (c1, c2)
);
Per quanto riguarda il tuo commento: "fare in modo che un PK utilizzi un indice denominato", il codice sopra riportato farà sì che l'indice della chiave primaria venga chiamato "PK_c".
La chiave primaria e la chiave di clustering non devono essere le stesse colonne. Puoi definirli separatamente. Nell'esempio sopra, cambia la CLUSTERED
parola chiave in NONCLUSTERED
, quindi aggiungi semplicemente un indice cluster usando la CREATE INDEX
sintassi:
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 l'indice cluster è la tabella, sono tutti uguali. Un indice cluster definisce l'ordine logico delle righe memorizzate nella tabella. Nel mio primo esempio, le righe sono memorizzate nell'ordine dei valori delle colonne c1
e c2
. Poiché la chiave di clustering è anche definita come chiave primaria, la combinazione di c1
e c2
deve essere unica a livello di tabella.
Nel secondo esempio, la chiave primaria è composta dalle colonne c1
e c2
, tuttavia la chiave di clustering è solo la c2
colonna. Poiché non ho specificato l' UNIQUE
attributo CREATE INDEX
nell'istruzione, la chiave di clustering ( c2
) non deve essere univoca in tutta la tabella. Un "uniquifier" verrà creato automaticamente da SQL Server e aggiunto ai valori nella c2
colonna per creare la chiave di clustering. Questa chiave di clustering, poiché ora è unica, verrà quindi utilizzata come ID di riga in altri indici creati nella tabella.
Al fine di dimostrare i controlli chiave di clustering il layout di righe in deposito, è possibile utilizzare la funzione non documentata, fn_PhysLocCracker(%%PHYSLOC%%)
. Il codice seguente mostra che le righe sono disposte sul disco in ordine di c2
colonna, che ho definito come chiave di clustering:
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;
I risultati dal mio tempdb sono:
Nell'immagine sopra, le prime tre colonne vengono emesse dalla fn_PhysLocCracker
funzione, mostrando l'ordine fisico delle righe sul disco. Puoi vedere che il slot_id
valore aumenta il passo di blocco con il c2
valore, che è la chiave di clustering. L'indice della chiave primaria memorizza le righe in un ordine diverso, che può essere visto forzando SQL Server a restituire risultati dalla scansione della chiave primaria:
SELECT pkt.c1
, pkt.c2
FROM dbo.PKTest pkt WITH (INDEX = PK_PKTest, FORCESCAN);
Nota, non ho usato una ORDER BY
clausola nell'istruzione precedente poiché sto tentando di mostrare l'ordine degli elementi nell'indice della chiave primaria.
L'output della query sopra è:
Osservando la fn_PhysLocCracker
funzione, possiamo vedere l'ordine fisico dell'indice della chiave primaria.
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;
Poiché stiamo leggendo esclusivamente dall'indice stesso, vale a dire che nessuna colonna esterna all'indice viene referenziata nella query, i %%PHYSLOC%%
valori rappresentano le pagine dell'indice stesso.
I risultati:
create table c (c1 int not null primary key, c2 int)