2014-05-08 12 views
88

Jak mogę zrozumieć documentation następujące definicje są równoważne:Postgres UNIQUE vs indeksu

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

Jednak można przeczytać w notatce: preferowanym sposobem dodawania unique do tabeli jest ALTER TABLE. .. DODAJ KONSTRAKT. Używanie indeksów do wymuszania wyjątkowych ograniczeń może być uważane za szczegóły implementacji, do których nie należy uzyskiwać bezpośredniego dostępu..

Czy to tylko kwestia dobrego stylu? Jakie są praktyczne konsekwencje wyboru jednego z tych wariantów (na przykład pod względem wydajności)?

+19

The (tylko) różnica praktyczna jest, że można utworzyć klucz obcy do unikalnej przymusu, ale nie do unikalnego indeksu. –

+20

Zaletą na odwrót ([pojawił się ostatnio w innym pytaniu] (http://stackoverflow.com/a/23449309/157957)) jest to, że możesz mieć * częściowy * unikatowy indeks, taki jak "Unikatowy (foo) Gdzie bar jest pusty ". AFAIK, nie da się tego zrobić z przymusem. – IMSoP

+0

[tutaj] (http://flatiron.engineering/technology/2016/09/13/uniqueness-in-postgres.html) fajny artykuł na temat różnicy –

Odpowiedz

82

Miałem pewne wątpliwości co do tego podstawowego, ale ważnego problemu, więc postanowiłem uczyć się przez przykład.

Stwórzmy tabeli testowej mistrza z dwoma kolumnami, con_id z unikalność i ind_id indeksowane przez unikalnego indeksu.

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) 

W opisie tabeli (\ d w psql) można określić unikalne ograniczenie z unikalnego indeksu.

check wyjątkowość wyjątkowość

Miejmy, na wszelki wypadek.

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

Działa zgodnie z oczekiwaniami!

klucze obce

Teraz będziemy definiować fragment stół dwa klucze obce odniesienie do naszych dwóch kolumnach w mistrza.

Cóż, bez błędów. Upewnijmy się, że to działa.

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

Do obu kolumn można się odwoływać w kluczach obcych.

Ograniczenie stosując wskaźnik

Możesz dodać stołowego ograniczenie wykorzystania istniejącej unikatowy indeks.

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) 

Teraz nie ma różnicy między opisem ograniczeń kolumn.

cząstkowe indeksy

W deklaracji więzów tabeli nie można utworzyć częściowe indeksów. Pochodzi bezpośrednio z definition z create table .... W unikatowej deklaracji indeksu można ustawić WHERE clause, aby utworzyć indeks częściowy. Możesz także create index na wyrażenie (nie tylko na kolumnie) i zdefiniować kilka innych parametrów (sortowanie, porządek sortowania, umieszczanie wartości NULL).

Nie można dodać ograniczenia tabeli za pomocą częściowego indeksu.

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

Jeszcze jedna zaleta korzystania UNIQUE INDEX Vs. UNIQUE CONSTRAINT jest to, że można łatwo DROP/CREATE indeks CONCURRENTLY, zaś z przymusu nie można.

+2

AFAIK nie można jednocześnie zrzucić unikalnego indeksu. https://www.postgresql.org/docs/9.3/static/sql-dropindex.html "Podczas korzystania z tej opcji należy pamiętać o kilku zastrzeżeniach, można podać tylko jedną nazwę indeksu, a opcja CASCADE nie jest obsługiwana (W związku z tym indeks, który obsługuje ograniczenie UNIQUE lub PRIMARY KEY, nie może zostać usunięty w ten sposób.) " –

2

Jedność jest ograniczeniem. Zdarza się, że jest on implementowany poprzez utworzenie unikalnego indeksu, ponieważ indeks jest w stanie szybko przeszukać wszystkie istniejące wartości w celu ustalenia, czy dana wartość już istnieje.

W ujęciu koncepcyjnym indeks jest szczegółem implementacji, a niepowtarzalność powinna być powiązana tylko z ograniczeniami.

The full text

Więc wydajność prędkość powinna być taka sama

Powiązane problemy