Quando dovrei usare un vincolo univoco invece di un indice univoco?


195

Quando voglio che una colonna abbia valori distinti, posso usare un vincolo

create table t1(
id int primary key,
code varchar(10) unique NULL
);
go

oppure posso usare un indice univoco

create table t2(
id int primary key,
code varchar(10) NULL
);
go

create unique index I_t2 on t2(code);

Le colonne con vincoli univoci sembrano essere buoni candidati per indici univoci.

Esistono motivi noti per utilizzare vincoli univoci e non utilizzare indici univoci?


9
sono effettivamente diversi? Penso che in alcuni database, ad esempio postgresql, un vincolo unico crei semplicemente un indice univoco. Non sto rispondendo perché non so nulla del server SQL.
xenoterracide,

6
in postgresql, puoi usare un'espressione in un indice univoco ma non in un vincolo univoco.
Neil McGuigan,

1
Su MS SQL, sono implementati allo stesso modo. Prova a creare due tabelle con gli stessi dati, una con un vincolo univoco, l'altra con un indice univoco. Utilizzeranno la stessa quantità di spazio dell'indice ed entrambi saranno in grado di cercare l'indice univoco che (in pratica) viene creato in entrambi i modi.
Jon of All Trades,

Risposte:


153

Sotto il cofano viene implementato un vincolo univoco allo stesso modo di un indice univoco: è necessario un indice per soddisfare efficacemente il requisito di imporre il vincolo. Anche se l'indice viene creato come risultato di un vincolo UNIQUE, il pianificatore di query può utilizzarlo come qualsiasi altro indice se lo vede come il modo migliore per avvicinarsi a una determinata query.

Quindi, per un database che supporta entrambe le funzionalità, la scelta di quale utilizzare spesso dipenderà dallo stile e dalla coerenza preferiti.

Se hai intenzione di utilizzare l'indice come indice (ad esempio, il tuo codice potrebbe fare affidamento sulla ricerca / ordinamento / filtro su quel campo per essere veloce) Vorrei usare esplicitamente un indice univoco (e commentare la fonte) piuttosto che un vincolo per renderlo chiaro: in questo modo se il requisito di unicità viene modificato in una revisione successiva dell'applicazione che l'utente (o qualche altro programmatore) saprà per assicurarsi che un indice non univoco venga inserito al posto di quello univoco (rimuovendo semplicemente un vincolo univoco rimuoveresti l'indice completamente). Inoltre, un indice specifico può essere nominato in un suggerimento indice (ad esempio WITH (INDEX (ix_index_name)), che non credo sia il caso dell'indice creato dietro le quinte per la gestione dell'unicità poiché è improbabile che tu ne conosca il nome.

Allo stesso modo se hai solo bisogno di imporre l'unicità come regola aziendale piuttosto che il campo che deve essere cercato o utilizzato per l'ordinamento, allora userei il vincolo, ancora una volta per rendere l'uso previsto più ovvio quando qualcun altro guarda la definizione della tabella.

Si noti che se si utilizzano sia un vincolo univoco che un indice univoco sullo stesso campo, il database non sarà abbastanza luminoso da vedere la duplicazione, quindi si otterranno due indici che consumeranno spazio extra e rallenteranno gli inserimenti / gli aggiornamenti delle righe.


1
Mi chiedo "il database non sarà abbastanza luminoso"? È vero per tutti gli RDBMS? È obbligatorio per lo standard SQL? E anche se lo è (e mi chiedo perché dovrebbe essere), tutte le implementazioni lo implementano in questo modo? Oppure: perché un DB non può essere abbastanza "luminoso"?
Jürgen A. Erhard,

4
@jae: un DBMS sicuramente potrebbe essere abbastanza luminoso, ma dovresti verificare con ogni DBMS per vedere se lo è. Se chiedi a MSSQL di creare due indici identici, ne verranno creati due anziché uno a cui fanno riferimento due nomi (almeno questo è accaduto l'ultima volta che ho notato una situazione del genere (a causa di un errore di copia + incolla da parte mia)), quindi presumo lo stesso è il caso se uno degli indici è presente a causa di un vincolo.
David Spillett,

3
+1 @David Spillett Penso che fondamentalmente il DBMS presupponga solo che tu sappia cosa stai facendo; Se hai voglia di creare lo stesso indice due volte, non ti viene in dubbio.
Andrew Barber,

2
molto perspicace. Sai per caso se questo comportamento è presente anche in MySQL e Apache Derby?
corsiKa

5
È possibile nominare un vincolo e usarlo in un suggerimento indice. CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1. Gli indici possono essere più flessibili anche se in quanto i vincoli non supportano tutte le opzioni di indice come INCLUDEcolonne d o indici filtrati.
Martin Smith,

101

Oltre ai punti in altre risposte, ecco alcune differenze chiave tra i due.

Nota: i messaggi di errore provengono da SQL Server 2012.

Errori

La violazione di un vincolo univoco restituisce l'errore 2627.

Msg 2627, Level 14, State 1, Line 1
Violation of UNIQUE KEY constraint 'P1U_pk'. Cannot insert duplicate key in object 'dbo.P1U'. The duplicate key value is (1).
The statement has been terminated.

La violazione di un indice univoco restituisce l'errore 2601.

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.P1' with unique index 'P1_u'. The duplicate key value is (1).
The statement has been terminated.

Disattivazione

Un vincolo univoco non può essere disabilitato.

Msg 11415, Level 16, State 1, Line 1
Object 'P1U_pk' cannot be disabled or enabled. This action applies only to foreign key and check constraints.
Msg 4916, Level 16, State 0, Line 1
Could not enable or disable the constraint. See previous errors.

Ma l'indice univoco dietro un vincolo di chiave primaria o un vincolo univoco può essere disabilitato, così come qualsiasi indice univoco. Hat-tip Brain2000.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

Si noti il ​​solito avviso che la disabilitazione di un indice cluster rende inaccessibili i dati.

Opzioni

Vincoli univoci supportano opzioni di indicizzazione come FILLFACTORe IGNORE_DUP_KEY, sebbene ciò non sia avvenuto per tutte le versioni di SQL Server.

Colonne incluse

Gli indici non cluster possono includere colonne non indicizzate (definito indice di copertura, questo è un importante miglioramento delle prestazioni). Gli indici dietro i vincoli PRIMARY KEY e UNIQUE non possono includere colonne. Hat-tip @ypercube.

filtraggio

Un vincolo univoco non può essere filtrato.

È possibile filtrare un indice univoco.

CREATE UNIQUE NONCLUSTERED INDEX Students6_DrivesLicence_u 
ON dbo.Students6( DriversLicenceNo ) WHERE DriversLicenceNo is not null ;

Vincoli di chiave esterna

Un vincolo di chiave esterna non può fare riferimento a un indice univoco filtrato, sebbene possa fare riferimento a un indice univoco non filtrato (penso che sia stato aggiunto in SQL Server 2005).

Naming

Quando si crea un vincolo, specificare un nome di vincolo è facoltativo (per tutti e cinque i tipi di vincoli). Se non specifichi un nome, MSSQL ne genererà uno per te.

CREATE TABLE dbo.T1 (
    TID int not null PRIMARY KEY
) ;
GO
CREATE TABLE dbo.T2 (
    TID int not null CONSTRAINT T2_pk PRIMARY KEY
) ;

Durante la creazione di indici, è necessario specificare un nome.

Hat-tip @ i-one.

link

http://technet.microsoft.com/en-us/library/aa224827(v=SQL.80).aspx

http://technet.microsoft.com/en-us/library/ms177456.aspx


Un vincolo univoco può essere disabilitato e abilitato con lo stesso metodo di un indice: ALTER INDEX tbl ON uconstraint DISABLE, ALTER INDEX tbl ON uconstraint REBUILD
Brain2000

Grazie @ Brain2000. Per coincidenza, stamattina ho insegnato una sezione sulla disabilitazione degli indici prima di leggere questo commento.
Greenstone Walker,

10

Per citare MSDN come fonte autorevole:

Non ci sono differenze significative tra la creazione di un vincolo UNICO e la creazione di un indice univoco indipendente da un vincolo . La convalida dei dati avviene allo stesso modo e Query Optimizer non distingue tra un indice univoco creato da un vincolo o creato manualmente. Tuttavia, la creazione di un vincolo UNICO sulla colonna chiarisce l'obiettivo dell'indice ... maggiori informazioni qui

E...

Motore di database crea automaticamente un indice UNIQUE per applicare il requisito di unicità del vincolo UNIQUE. Pertanto, se si tenta di inserire una riga duplicata, Motore di database restituisce un messaggio di errore che indica che il vincolo UNIQUE è stato violato e non aggiunge la riga alla tabella. A meno che un indice cluster non sia esplicitamente specificato, un indice univoco e non cluster viene creato per impostazione predefinita per applicare il vincolo UNIQUE ... maggiori informazioni qui

Altro in: https://technet.microsoft.com/en-us/library/aa224827%28v=sql.80%29.aspx


6

Una delle principali differenze tra un vincolo univoco e un indice univoco è che un vincolo di chiave esterna su un'altra tabella può fare riferimento a colonne che costituiscono un vincolo univoco. Questo non è vero per gli indici univoci. Inoltre, i vincoli univoci sono definiti come parte dello standard ANSI, mentre gli indici no. Infine, si ritiene che un vincolo unico risieda nel regno della progettazione logica del database (che può essere implementato in modo diverso da motori DB diversi) mentre l'indice è un aspetto fisico. Pertanto, il vincolo univoco è più dichiarativo. Preferirei un vincolo unico in quasi tutti i casi.


8
-1 In SQL Server è errato quanto segue: "un vincolo di chiave esterna su un'altra tabella può fare riferimento a colonne che costituiscono un vincolo univoco. Questo non è vero per gli indici univoci". In SQL Server, possiamo riferire i vincoli FK a indici univoci.
AK,

4
Penso che la possibilità per un vincolo di chiave esterna di fare riferimento a un indice univoco sia stata aggiunta in SQL Server 2005. Molte fonti, incluse alcune pagine in BOL, non sono state aggiornate per riflettere le modifiche, quindi non credo che la risposta di Dmitry merita i voti negativi. Il resto della sua risposta è perfetto: i vincoli sono standard ANSI, gli indici no.
Greenstone Walker,

nonostante questi downvotes la mia risposta preferita.
miracle173,

Gli standard sono importanti. Se gli standard Ansi devono utilizzare un vincolo univoco, allora dovremmo utilizzare un vincolo univoco.
Rhyous,

1

In Oracle una grande differenza è che puoi creare un indice univoco di funzione, che non è fattibile con vincoli univoci:

Per esempio

create unique index ux_test on my_table (case when amount != 0 then fk_xyz end);

Quindi fk_xyzè unico solo per i record che hanno amount != 0.


7
In SQL Server (il tag della domanda), gli indici possono essere filtrati con una WHEREclausola. CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
Greenstone Walker,

-3

Il vincolo UNIQUE è preferito rispetto all'indice UNIQUE. Quando il vincolo non è univoco, è necessario utilizzare un indice regolare o non univoco. Il vincolo è anche un altro tipo di indice. L'indice viene utilizzato per un accesso più rapido.

Gli indici univoci possono avere clausole where. Ad esempio, è possibile creare indici per ogni anno in base alla colonna della data

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'

È bello vedere il vantaggio della clausola where menzionato.
crokusek,

3
"Il vincolo è anche un altro tipo di indice." No, non lo è. Alcuni vincoli (PK, UQ, FK) possono essere e sono spesso applicati dall'uso di indici. Non necessariamente però e non di default in tutti i DBMS.
ypercubeᵀᴹ
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.