Jak rozumiem dokumentację, poniższe definicje są równoważne:
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 uwaga w podręczniku Postgres 9.4 mówi:
Preferowanym sposobem dodania unikatowego ograniczenia do tabeli jest
ALTER TABLE ... ADD CONSTRAINT
. Stosowanie indeksów do wymuszania unikatowych ograniczeń można uznać za szczegół implementacji, do którego nie należy uzyskiwać bezpośredniego dostępu.
(Edycja: ta notatka została usunięta z podręcznika wraz z Postgres 9.5.)
Czy to tylko kwestia dobrego stylu? Jakie są praktyczne konsekwencje wyboru jednego z tych wariantów (np. W wykonaniu)?
sql
postgresql
unique
Adam Piotrowski
źródło
źródło
Odpowiedzi:
Miałem wątpliwości co do tej podstawowej, ale ważnej kwestii, więc postanowiłem uczyć się na przykładzie.
Utwórzmy wzorzec tabeli testowej z dwiema kolumnami, con_id z unikalnym ograniczeniem i ind_id indeksowanym przez unikalny indeks.
W opisie tabeli (\ d w psql) można odróżnić unikalne ograniczenie z unikalnego indeksu.
Wyjątkowość
Sprawdźmy na wszelki wypadek wyjątkowość.
Działa zgodnie z oczekiwaniami!
Klucz obcy
Teraz zdefiniujemy tabelę szczegółów z dwoma kluczami obcymi odwołującymi się do naszych dwóch kolumn w master .
Cóż, żadnych błędów. Upewnijmy się, że to działa.
Do obu kolumn można się odwoływać w kluczach obcych.
Ograniczenie za pomocą indeksu
Możesz dodać ograniczenie tabeli za pomocą istniejącego unikalnego indeksu.
Teraz nie ma różnicy między opisem ograniczeń kolumny.
Indeksy częściowe
W deklaracji ograniczeń tabeli nie można tworzyć indeksów częściowych. Pochodzi bezpośrednio z definicji z
create table ...
. W unikalnej deklaracji indeksu można ustawićWHERE clause
tworzenie indeksu częściowego. Możesz również utworzyć indeks na wyrażeniu (nie tylko na kolumnie) i zdefiniować inne parametry (sortowanie, porządek sortowania, umieszczanie wartości NULL).Nie można dodać ograniczenia tabeli przy użyciu indeksu częściowego.
źródło
Kolejną zaletą używania
UNIQUE INDEX
vs.UNIQUE CONSTRAINT
jest to, że możesz łatwoDROP
/CREATE
indeksowaćCONCURRENTLY
, podczas gdy z ograniczeniem nie możesz.źródło
Pełny tekst
Więc wydajność prędkości powinna być taka sama
źródło
Inną rzeczą, z którą się spotkałem, jest to, że możesz używać wyrażeń sql w unikalnych indeksach, ale nie w ograniczeniach.
Więc to nie działa:
ale następujące prace.
źródło
citext
rozszerzenia.Ponieważ różni ludzie zapewniają przewagę unikalnych indeksów nad unikalnymi ograniczeniami, tutaj jest wada: unikalne ograniczenie można odroczyć (sprawdzane tylko na końcu transakcji), unikalnego indeksu nie można.
źródło
Przeczytałem to w dokumencie:
Myślę więc, że jest to coś, co nazywasz „częściową wyjątkowością”, dodając ograniczenie.
A jak zadbać o wyjątkowość:
Powinniśmy więc dodać ograniczenie, które tworzy indeks, aby zapewnić unikalność.
Jak widzę ten problem?
„Ograniczenie” ma na celu gramatyczne zapewnienie, że ta kolumna będzie niepowtarzalna, ustanawia prawo, regułę; podczas gdy „indeks” jest semantyczny , dotyczy tego, „jak wdrożyć, jak osiągnąć wyjątkowość, co oznacza unikalność, jeśli chodzi o implementację”. Tak więc sposób, w jaki Postgresql to implementuje, jest bardzo logiczny: najpierw deklarujesz, że kolumna powinna być unikalna, a następnie Postgresql dodaje implementację dodawania unikalnego indeksu .
źródło
where
klauzuli, więc można zdefiniować, że rekordy są unikalne. IFF spełniają pewne kryteria. To po prostu wyłącza ograniczenia dla niezdefiniowanego zestawu rekordów, które poprzedzają utworzenie ograniczenia. Jest zupełnie inaczej, a ta ostatnia jest znacznie mniej przydatna, choć wydaje mi się, że jest wygodna w przypadku migracji progresywnych.Istnieje różnica w blokowaniu.
Dodanie indeksu nie blokuje dostępu do odczytu do tabeli.
Dodanie ograniczenia powoduje zablokowanie tabeli (więc wszystkie selekcje są blokowane), ponieważ jest ono dodawane za pośrednictwem ALTER TABLE .
źródło
Bardzo drobną rzeczą, którą można zrobić tylko z ograniczeniami, a nie z indeksami, jest użycie
ON CONFLICT ON CONSTRAINT
klauzuli ( zobacz również to pytanie ).To nie działa:
Produkuje:
Zmień indeks w ograniczenie:
To
INSERT
stwierdzenie teraz działa.źródło