Equivalente di SQL Server della clausola Oracle USING INDEX


9

Esiste un equivalente di SQL Server 2008 della clausola USING INDEX in Oracle? In particolare per il costrutto:

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;

Nella Documentazione SQL Server sugli indici univoci afferma (enfasi aggiunta):

Gli indici univoci vengono implementati nei seguenti modi:

CHIAVE PRIMARIA o vincolo UNICO

Quando si crea un vincolo PRIMARY KEY, viene creato automaticamente un indice cluster univoco sulla colonna o sulle colonne se un indice cluster sulla tabella non esiste già e non si specifica un indice univoco non cluster . La colonna chiave primaria non può consentire valori NULL.

Il che sembra implicare che esiste un modo per specificare quale indice deve essere usato per una chiave primaria.


Basta definire il PK insieme alla tabella. create table c (c1 int not null primary key, c2 int)
a_horse_with_no_name

È la parte "fare in modo che un PK usi un indice denominato" che mi interessa.
Nik

No, non c'è modo di farlo. Una chiave primaria è un vincolo e un indice. In quello che hai fornito la chiave primaria sarebbe di default un indice cluster univoco. Il che renderebbe l'altro indice definito un duplicato a meno che tu non includessi sia c1 che c2 nella clausola where.
Aaron,

Risposte:


7

Esiste un equivalente di SQL Server 2008 della clausola USING INDEX in Oracle?

No. Quando si crea una chiave primaria o un vincolo univoco in SQL Server, viene creato automaticamente un indice univoco per supportare tale vincolo, con le stesse chiavi.

Il che sembra implicare che esiste un modo per specificare quale indice deve essere usato per una chiave primaria.

No. La documentazione sta solo tentando di spiegare se l'indice di supporto automatico verrà creato come cluster o non cluster, se non specificato. È formulato in modo confuso, sono d'accordo.

Per chiarire, quando si aggiunge un vincolo di chiave primaria a una tabella esistente senza esprimere una preferenza, l'indice di supporto verrà raggruppato se non esiste un indice cluster preesistente sulla tabella. L'indice di supporto verrà creato come non cluster se esiste già un indice cluster

È possibile richiedere in modo specifico una chiave primaria cluster o non cluster utilizzando: PRIMARY KEY CLUSTEREDo PRIMARY KEY NONCLUSTERED.

In tutta onestà, la documentazione è molto più chiara sull'argomento in:

table_constraint (Transact-SQL)


5

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 CLUSTEREDparola chiave in NONCLUSTERED, quindi aggiungi semplicemente un indice cluster usando la CREATE INDEXsintassi:

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 c1e c2. Poiché la chiave di clustering è anche definita come chiave primaria, la combinazione di c1e c2deve essere unica a livello di tabella.

Nel secondo esempio, la chiave primaria è composta dalle colonne c1e c2, tuttavia la chiave di clustering è solo la c2colonna. Poiché non ho specificato l' UNIQUEattributo CREATE INDEXnell'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 c2colonna 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 c2colonna, 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:

inserisci qui la descrizione dell'immagine

Nell'immagine sopra, le prime tre colonne vengono emesse dalla fn_PhysLocCrackerfunzione, mostrando l'ordine fisico delle righe sul disco. Puoi vedere che il slot_idvalore aumenta il passo di blocco con il c2valore, 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 BYclausola nell'istruzione precedente poiché sto tentando di mostrare l'ordine degli elementi nell'indice della chiave primaria.

L'output della query sopra è:

inserisci qui la descrizione dell'immagine

Osservando la fn_PhysLocCrackerfunzione, 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:

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.