2014-05-08 16 views
88

Come posso capire documentation le seguenti definizioni sono equivalenti:Postgres vincolo univoco vs indice

create table foo (
    id serial primary key, 
    code integer, 
    label text, 
    constraint foo_uq unique (code, label)); 

create table foo (
    id serial primary key, 
    code integer, 
    label text); 
create unique index foo_idx on foo using btree (code, label);  

Tuttavia si può leggere nella nota: Il modo migliore per aggiungere un vincolo univoco a una tabella è ALTER TABLE. .. Aggiungi Vincolo. L'uso di indici per imporre vincoli univoci potrebbe essere considerato un dettaglio di implementazione a cui non si dovrebbe accedere direttamente.

È solo una questione di stile? Quali sono le conseguenze pratiche della scelta di una di queste varianti (ad esempio in termini di prestazioni)?

+19

L'(solo) differenza pratica è che si può creare una chiave esterna per un vincolo univoco, ma non a un indice univoco. –

+20

Un vantaggio al contrario ([come riportato in un'altra domanda di recente] (http://stackoverflow.com/a/23449309/157957) è che puoi avere un indice univoco * parziale *, come "Unico (foo) Dove bar è Null ". AFAIK, non c'è modo di farlo con un vincolo. – IMSoP

+0

[Here] (http://flatiron.engineering/technology/2016/09/13/uniqueness-in-postgres.html) bel articolo sulla differenza –

risposta

82

Avevo qualche dubbio su questo problema fondamentale ma importante, quindi ho deciso di imparare dall'esempio.

Creiamo tabella di test maestro con due colonne, con_id con vincolo univoco e ind_id indicizzati da indice univoco.

create table master (
    con_id integer unique, 
    ind_id integer 
); 
create unique index master_unique_idx on master (ind_id); 

    Table "public.master" 
Column | Type | Modifiers 
--------+---------+----------- 
con_id | integer | 
ind_id | integer | 
Indexes: 
    "master_con_id_key" UNIQUE CONSTRAINT, btree (con_id) 
    "master_unique_idx" UNIQUE, btree (ind_id) 

In descrizione della tabella (\ d in psql) si può dire vincolo univoco da indice univoco.

controllo unicità Unicità

Let, per ogni evenienza.

test=# insert into master values (0, 0); 
INSERT 0 1 
test=# insert into master values (0, 1); 
ERROR: duplicate key value violates unique constraint "master_con_id_key" 
DETAIL: Key (con_id)=(0) already exists. 
test=# insert into master values (1, 0); 
ERROR: duplicate key value violates unique constraint "master_unique_idx" 
DETAIL: Key (ind_id)=(0) already exists. 
test=# 

Funziona come previsto!

chiavi esterne

Ora definiremo dettaglio tavolo con due chiavi esterne riferimento ai nostri due colonne in maestro.

create table detail (
    con_id integer, 
    ind_id integer, 
    constraint detail_fk1 foreign key (con_id) references master(con_id), 
    constraint detail_fk2 foreign key (ind_id) references master(ind_id) 
); 

    Table "public.detail" 
Column | Type | Modifiers 
--------+---------+----------- 
con_id | integer | 
ind_id | integer | 
Foreign-key constraints: 
    "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id) 
    "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id) 

Bene, nessun errore. Assicuriamoci che funzioni.

test=# insert into detail values (0, 0); 
INSERT 0 1 
test=# insert into detail values (1, 0); 
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk1" 
DETAIL: Key (con_id)=(1) is not present in table "master". 
test=# insert into detail values (0, 1); 
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk2" 
DETAIL: Key (ind_id)=(1) is not present in table "master". 
test=# 

Entrambe le colonne possono essere referenziate in chiavi esterne.

vincolo utilizzando indice

È possibile aggiungere vincolo di tabella con indice univoco esistente.

alter table master add constraint master_ind_id_key unique using index master_unique_idx; 

    Table "public.master" 
Column | Type | Modifiers 
--------+---------+----------- 
con_id | integer | 
ind_id | integer | 
Indexes: 
    "master_con_id_key" UNIQUE CONSTRAINT, btree (con_id) 
    "master_ind_id_key" UNIQUE CONSTRAINT, btree (ind_id) 
Referenced by: 
    TABLE "detail" CONSTRAINT "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id) 
    TABLE "detail" CONSTRAINT "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id) 

Ora non c'è differenza tra la descrizione dei vincoli di colonna.

indici parziali

In tabella di dichiarazione di vincolo non è possibile creare indici parziali. Viene direttamente dallo definition di create table .... Nella dichiarazione indice univoca è possibile impostare WHERE clause per creare un indice parziale. È anche possibile create index all'espressione (non solo sulla colonna) e definire altri parametri (fascicolazione, ordinamento, posizionamento NULL).

Non è possibile aggiungere un vincolo di tabella utilizzando l'indice parziale.

alter table master add column part_id integer; 
create unique index master_partial_idx on master (part_id) where part_id is not null; 

alter table master add constraint master_part_id_key unique using index master_partial_idx; 
ERROR: "master_partial_idx" is a partial index 
LINE 1: alter table master add constraint master_part_id_key unique ... 
          ^
DETAIL: Cannot create a primary key or unique constraint using such an index. 
21

più Uno dei vantaggi di UNIQUE INDEX vs. UNIQUE CONSTRAINT è che si può facilmente DROP/CREATE un indice CONCURRENTLY, mentre con un vincolo non si può.

+2

AFAIK non è possibile rilasciare contemporaneamente un indice univoco. https://www.postgresql.org/docs/9.3/static/sql-dropindex.html "Ci sono molte avvertenze da tenere presente quando si utilizza questa opzione. È possibile specificare solo un nome indice e l'opzione CASCADE non è supportata . (Quindi, un indice che supporti un vincolo UNIQUE o PRIMARY KEY non può essere eliminato in questo modo). " –

2

L'unicità è un vincolo. Accade per essere implementato tramite la creazione di un indice univoco poiché un indice è in grado di cercare rapidamente tutti i valori esistenti per determinare se esiste già un determinato valore.

Concettualmente l'indice è un dettaglio di implementazione e l'univocità deve essere associato solo con i vincoli.

The full text

Così prestazioni di velocità dovrebbe essere lo stesso