Karena saya dapat memahami dokumentasi , definisi berikut ini setara:
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);
Namun, catatan dalam manual untuk Postgres 9.4 mengatakan:
Cara yang disukai untuk menambahkan batasan unik ke tabel adalah
ALTER TABLE ... ADD CONSTRAINT
. Penggunaan indeks untuk menegakkan batasan unik dapat dianggap sebagai detail implementasi yang tidak boleh diakses secara langsung.
(Edit: catatan ini telah dihapus dari manual dengan Postgres 9.5.)
Apakah ini hanya masalah gaya yang baik? Apa konsekuensi praktis dari pilihan salah satu varian ini (misalnya dalam kinerja)?
sql
postgresql
unique
Adam Piotrowski
sumber
sumber
Jawaban:
Saya memiliki keraguan tentang masalah mendasar namun penting ini, jadi saya memutuskan untuk belajar dengan memberi contoh.
Mari kita buat master tabel uji dengan dua kolom, con_id dengan kendala unik dan ind_id diindeks oleh indeks unik.
Dalam deskripsi tabel (\ d dalam psql), Anda dapat memberi tahu batasan unik dari indeks unik.
Keunikan
Mari kita periksa keunikannya, untuk berjaga-jaga.
Ini berfungsi seperti yang diharapkan!
Kunci asing
Sekarang kita akan mendefinisikan tabel detail dengan dua kunci asing yang merujuk ke dua kolom kita di master .
Yah, tidak ada kesalahan. Mari kita pastikan itu berhasil.
Kedua kolom dapat direferensikan dalam kunci asing.
Batasi menggunakan indeks
Anda bisa menambahkan batasan tabel menggunakan indeks unik yang ada.
Sekarang tidak ada perbedaan antara deskripsi batasan kolom.
Indeks sebagian
Dalam deklarasi kendala tabel Anda tidak dapat membuat indeks parsial. Ini datang langsung dari definisi dari
create table ...
. Dalam deklarasi indeks unik Anda dapat mengaturWHERE clause
untuk membuat indeks parsial. Anda juga dapat membuat indeks pada ekspresi (tidak hanya pada kolom) dan menentukan beberapa parameter lainnya (susunan, susunan urutan, penempatan NULLs).Anda tidak bisa menambahkan batasan tabel menggunakan indeks parsial.
sumber
Satu lagi keuntungan menggunakan
UNIQUE INDEX
vs.UNIQUE CONSTRAINT
adalah bahwa Anda dapat dengan mudahDROP
/CREATE
indeksCONCURRENTLY
, sedangkan dengan kendala Anda tidak bisa.sumber
Teks lengkap
Jadi kinerja kecepatan harus sama
sumber
Hal lain yang saya temui adalah bahwa Anda dapat menggunakan ekspresi sql dalam indeks unik tetapi tidak dalam kendala.
Jadi, ini tidak berfungsi:
tetapi mengikuti karya.
sumber
citext
ekstensi.Karena berbagai orang telah memberikan keuntungan dari indeks unik daripada kendala unik, inilah kelemahannya: kendala unik dapat ditangguhkan (hanya diperiksa pada akhir transaksi), indeks unik tidak dapat.
sumber
Saya membaca ini di dokumen:
Jadi saya pikir itu adalah apa yang Anda sebut "keunikan parsial" dengan menambahkan kendala.
Dan, tentang cara memastikan keunikan:
Jadi kita harus menambahkan batasan, yang menciptakan indeks, untuk memastikan keunikan.
Bagaimana saya melihat masalah ini?
Sebuah "kendala" bertujuan untuk gramatically memastikan bahwa kolom ini harus unik, itu menetapkan hukum, aturan; sementara "indeks" bersifat semantik , tentang "bagaimana menerapkan, bagaimana mencapai keunikan, apa artinya unik ketika datang ke implementasi". Jadi, cara Postgresql mengimplementasikannya, sangat logis: pertama, Anda menyatakan bahwa sebuah kolom harus unik, kemudian, Postgresql menambahkan penerapan penambahan indeks unik untuk Anda .
sumber
where
klausa, sehingga Anda dapat mendefinisikan bahwa catatan adalah IFF unik yang memenuhi beberapa kriteria. Ini hanya menonaktifkan batasan untuk set rekaman yang tidak ditentukan yang mendahului kendala yang sedang dibuat. Ini benar-benar berbeda, dan yang terakhir ini secara signifikan kurang berguna, walaupun saya rasa nyaman untuk migrasi progresif.Ada perbedaan dalam penguncian.
Menambahkan indeks tidak memblokir akses baca ke tabel.
Menambahkan batasan tidak menempatkan kunci tabel (sehingga semua pilihan diblokir) karena ditambahkan melalui ALTER TABLE .
sumber
Suatu hal yang sangat kecil yang dapat dilakukan dengan kendala saja dan tidak dengan indeks menggunakan
ON CONFLICT ON CONSTRAINT
klausa ( lihat juga pertanyaan ini ).Ini tidak berfungsi:
Itu menghasilkan:
Ubah indeks menjadi batasan:
Dan
INSERT
pernyataan itu sekarang berfungsi.sumber