2014-05-08 3 views
88

Comme je comprends documentation les définitions suivantes sont équivalentes:Postgres contrainte unique 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);  

Cependant, vous pouvez lire dans la note: La meilleure façon d'ajouter une contrainte unique à une table est ALTER TABLE. .. AJOUTER CONTRAINTE. L'utilisation d'index pour appliquer des contraintes uniques peut être considérée comme un détail d'implémentation auquel il n'est pas possible d'accéder directement.

Est-ce seulement une question de style? Quelles sont les conséquences pratiques du choix de l'une de ces variantes (par exemple dans la performance)?

+19

La (seule) différence pratique est que vous pouvez créer une clé étrangère à une contrainte unique, mais pas à un index unique. –

+20

Un avantage dans l'autre sens ([comme cela est arrivé récemment dans une autre question] (http://stackoverflow.com/a/23449309/157957)) est que vous pouvez avoir un index unique * partial *, comme "Unique (foo) Où la barre est nulle ". AFAIK, il n'y a aucun moyen de le faire avec une contrainte. – IMSoP

+0

[ici] (http://flatiron.engineering/technology/2016/09/13/uniqueness-in-postgres.html) bel article sur la différence –

Répondre

82

J'avais des doutes sur ce problème basique mais important, j'ai donc décidé d'apprendre par l'exemple.

Créons table de test maître avec deux colonnes, CON_ID avec contrainte unique et ind_id indexé par index unique.

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) 

Dans la description de la table (\ d en psql), vous pouvez indiquer une contrainte unique à partir d'un index unique.

Unicité

Soit l'unicité de chèque, juste au cas où.

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=# 

Cela fonctionne comme prévu!

clés étrangères

Maintenant, nous allons définir détail table avec deux clés étrangères faisant référence à nos deux colonnes dans maître.

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) 

Eh bien, pas d'erreurs. Assurons-nous que cela fonctionne.

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=# 

Les deux colonnes peuvent être référencées dans des clés étrangères.

Constraint utilisant l'index

Vous pouvez ajouter contrainte de table à l'aide index unique existant.

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) 

Il n'y a plus aucune différence entre les descriptions de contraintes de colonnes.

index partiels

Dans le tableau déclaration de contrainte que vous ne pouvez pas créer des index partiels. Il vient directement du definition de create table .... Dans une déclaration d'index unique, vous pouvez définir WHERE clause pour créer un index partiel. Vous pouvez également create index sur l'expression (pas seulement sur la colonne) et définir d'autres paramètres (classement, ordre de tri, placement des valeurs NULL).

Vous ne pouvez pas ajouter de contrainte de table à l'aide d'un index partiel.

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

Un autre avantage d'utiliser UNIQUE INDEX contre UNIQUE CONSTRAINT est que vous pouvez facilement DROP/CREATE un indice CONCURRENTLY, alors qu'avec une contrainte vous ne pouvez pas.

+2

AFAIK il n'est pas possible de supprimer simultanément un index unique. https://www.postgresql.org/docs/9.3/static/sql-dropindex.html "Il existe plusieurs avertissements à prendre en compte lors de l'utilisation de cette option: un seul nom d'index peut être spécifié et l'option CASCADE n'est pas prise en charge . (Ainsi, un index qui supporte une contrainte UNIQUE ou PRIMARY KEY ne peut pas être supprimé de cette façon.) " –

2

L'unicité est une contrainte. Il arrive d'être implémenté via la création d'un index unique car un index est rapidement capable de rechercher toutes les valeurs existantes afin de déterminer si une valeur donnée existe déjà.

Conceptuellement, l'index est un détail d'implémentation et l'unicité doit être associée uniquement aux contraintes.

The full text

donc la performance de vitesse devrait être la même