2014-05-08 13 views
88

Wie ich documentation die folgenden Definitionen sind äquivalent zu verstehen:Postgres eindeutige Einschränkung vs Index

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);  

auch immer Sie in der Notiz zu lesen: Die bevorzugte Art und Weise eine eindeutige Einschränkung auf eine Tabelle hinzuzufügen ALTER TABLE ist. .. HINZUFÜGEN. Die Verwendung von Indizes zum Erzwingen von eindeutigen Integritätsbedingungen könnte als Implementierungsdetail betrachtet werden, auf das nicht direkt zugegriffen werden soll..

Ist es nur eine Frage des guten Stils? Was sind praktische Konsequenzen der Wahl einer dieser Varianten (z. B. in der Leistung)?

+19

Die (nur) praktische Unterschied ist, dass Sie einen Fremdschlüssel zu einer einzigartigen Einschränkung erstellen kann, aber nicht auf einen eindeutigen Index. –

+20

Ein Vorteil umgekehrt ([wie kürzlich in einer anderen Frage kam] (http://Stackoverflow.com/a/23449309/157957)) ist, dass Sie einen * partiellen * eindeutigen Index haben können, z. B. "Unique (foo) Wo bar ist Null ". AFAIK, es gibt keine Möglichkeit, dies mit einer Einschränkung zu tun. – IMSoP

+0

[hier] (http://flatiron.engineering/technology/2016/09/13/uniqueness-in-postgres.html) schönen Artikel über Unterschied –

Antwort

82

Ich hatte einige Zweifel über dieses grundlegende, aber wichtige Problem, also beschloss ich, mit gutem Beispiel zu lernen.

Lassen Sie sich Testtabelle Master mit zwei Spalten erstellen, con_id mit einzigartigem Zwang und ind_id durch eindeutigen Index indiziert.

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 der Tabellenbeschreibung (\ d in psql) können Sie eindeutige Einschränkung von eindeutigen Index angeben.

Einmaligkeit

Scheck Einzigartigkeit Lassen Sie uns, nur für den Fall.

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

Es funktioniert wie erwartet!

Fremdschlüssel

Jetzt werden wir Detail Tabelle mit zwei Fremdschlüssel verweist auf unsere zwei Spalten in Master definieren.

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) 

Nun, keine Fehler. Lassen Sie uns sicherstellen, dass es funktioniert.

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

Beide Spalten können in Fremdschlüsseln referenziert werden.

Constraint mit Index

Sie können Tabellenbedingung in einem der vorhandenen eindeutigen Index hinzuzufügen.

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) 

Jetzt gibt es keinen Unterschied mehr zwischen den Beschreibungen der Spaltenbeschränkungen.

Teilindizes

In Tabellenconstraint Deklaration Sie nicht Teilindizes erstellen können. Es kommt direkt aus der definitioncreate table .... In der eindeutigen Indexdeklaration können Sie WHERE clause einstellen, um Teilindex zu erstellen. Sie können auch create index auf Ausdruck (nicht nur auf Spalte) und definieren Sie einige andere Parameter (Sortierung, Sortierreihenfolge, NULLs Platzierung).

Sie können Tabelleneinschränkungen nicht mit Teilindex hinzufügen.

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

Ein weiterer Vorteil der Verwendung von UNIQUE INDEX vs. UNIQUE CONSTRAINT ist, dass man leicht DROP/CREATE ein Index CONCURRENTLY, während mit einer Einschränkung können Sie nicht.

+2

AFAIK es ist nicht möglich, gleichzeitig einen eindeutigen Index zu löschen. https://www.postgresql.org/docs/9.3/static/sql-dropindex.html „Es gibt mehrere Einschränkungen bewusst sein, wenn Sie diese Option verwenden. Nur ein Indexname angegeben werden kann, und die CASCADE-Option wird nicht unterstützt (Daher kann ein Index, der eine UNIQUE- oder PRIMARY KEY-Einschränkung unterstützt, auf diese Weise nicht gelöscht werden.) " –

2

Eindeutigkeit ist eine Einschränkung. Es wird zufällig über die Erstellung eines eindeutigen Index implementiert, da ein Index schnell alle vorhandenen Werte suchen kann, um festzustellen, ob ein bestimmter Wert bereits vorhanden ist.

Konzeptionell ist der Index ein Implementierungsdetail und die Eindeutigkeit sollte nur mit Einschränkungen verknüpft sein.

The full text

sollte also Geschwindigkeitsleistung gleich sein

Verwandte Themen