Saya punya meja yang mewakili film. Bidang adalah:
id (PK), title, genre, runtime, released_in, tags, origin, downloads
.
Basis data saya tidak dapat dicemari oleh baris yang digandakan, jadi saya ingin menegakkan keunikan. Masalahnya adalah bahwa film yang berbeda dapat memiliki judul yang sama, atau bahkan bidang yang sama kecuali tags
dan downloads
. Bagaimana cara menegakkan keunikan?
Saya memikirkan dua cara:
- buat semua bidang kecuali
downloads
kunci utama. Saya menahandownloads
karena JSON dan mungkin akan berdampak pada kinerja. - simpan hanya
id
sebagai kunci utama, tetapi tambahkan batasan unik dengan semua kolom lainnya (kecuali, sekali lagi,downloads
).
Saya membaca pertanyaan ini yang sangat mirip, tetapi saya tidak begitu mengerti apa yang harus saya lakukan. Saat ini tabel ini tidak terkait dengan tabel lain, tetapi di masa depan bisa jadi.
Saat ini saya memiliki kurang dari 20.000 catatan, tetapi saya berharap jumlahnya akan bertambah. Saya tidak tahu apakah ini agak relevan dengan masalah ini.
EDIT: Saya memodifikasi skema dan di sini adalah bagaimana saya akan membuat tabel:
CREATE TABLE movies (
id serial PRIMARY KEY,
title text NOT NULL,
runtime smallint NOT NULL CHECK (runtime >= 0),
released_in smallint NOT NULL CHECK (released_in > 0),
genres text[] NOT NULL default ARRAY[]::text[],
tags text[] NOT NULL default ARRAY[]::text[],
origin text[] NOT NULL default ARRAY[]::text[],
downloads json NOT NULL,
inserted_at timestamp NOT NULL default current_timestamp,
CONSTRAINT must_be_unique UNIQUE(title,runtime,released_in,genres,tags,origin)
);
Saya juga menambahkan timestamp
kolom, tapi itu tidak masalah karena saya tidak akan menyentuhnya. Jadi itu akan selalu otomatis dan unik.
Jawaban:
Definisi tabel Anda terlihat masuk akal sekarang. Dengan semua kolom
NOT NULL
,UNIQUE
kendala akan berfungsi seperti yang diharapkan - kecuali untuk kesalahan ketik dan perbedaan kecil dalam pengejaan, yang mungkin agak umum, saya khawatir. Pertimbangkan komentar @ a_horse .Alternatif dengan indeks unik fungsional
Pilihan lainnya adalah indeks unik fungsional (mirip dengan apa yang @Dave komentari ). Tetapi saya akan menggunakan
uuid
tipe data untuk mengoptimalkan ukuran dan kinerja indeks.Para pemain dari array ke teks tidak
IMMUTABLE
(karena implementasi generiknya):Karenanya, Anda memerlukan fungsi pembantu kecil untuk menyatakannya tidak berubah:
Gunakan untuk definisi indeks:
SQL Fiddle.
Keterangan lebih lanjut:
Anda mungkin menggunakan UUID yang dihasilkan sebagai PK, tetapi saya masih akan menggunakan
serial
kolom dengan 4 byte, yang sederhana dan murah untuk referensi FK dan tujuan lain. UUID akan menjadi pilihan bagus untuk sistem terdistribusi yang perlu menghasilkan nilai PK secara mandiri. Atau untuk meja yang sangat besar, tetapi tidak ada cukup film di tata surya kita untuk itu.Pro dan kontra
Sebuah kendala yang unik diimplementasikan dengan indeks yang unik pada terlibat kolom. Masukkan kolom yang relevan dalam definisi kendala terlebih dahulu dan Anda memiliki indeks yang berguna untuk tujuan lain sebagai manfaat jaminan.
Ada manfaat spesifik lainnya, berikut adalah daftar:
The indeks unik fungsional adalah (berpotensi jauh) lebih kecil dalam ukuran, yang dapat membuatnya secara substansial lebih cepat. Jika kolom Anda tidak terlalu besar, perbedaannya tidak akan banyak. Ada juga biaya overhead kecil untuk perhitungan.
Menggabungkan semua kolom dapat memperkenalkan false positive (
'foo ' || 'bar' = 'foob ' || 'ar'
, tapi sepertinya sangat tidak mungkin untuk kasus ini. Kesalahan ketik jauh lebih mungkin sehingga Anda dapat dengan aman mengabaikannya di sini.Keunikan dan susunan
Array harus disortir secara konsisten agar masuk akal dalam pengaturan unik yang bergantung pada
=
operator karena'{1,2}' <> '{2,1}'
. Saya sarankan mencari tabelgenre
,tag
danorigin
denganserial
PK dan entri unik, yang memungkinkan pencarian fuzzy untuk elemen array. Kemudian:baik menerapkan hubungan n: m yang dinormalisasi penuh yang juga memberikan integritas referensial. Keunikan setiap set referensi lebih sulit dibuat, Anda bisa menggunakan
MATERIALIZE VIEW
(MV) dengan array agregat sebagai batu loncatan.atau beroperasi dengan susunan referensi FK yang diurutkan (yang belum dapat didukung dengan kendala FK). Alat-alat dari intarray modul tambahan mungkin berguna:
Either way, bekerja dengan array secara langsung atau dengan skema yang dinormalisasi dan pandangan yang terwujud, pencarian bisa sangat efisien dengan indeks dan operator yang tepat:
Jika Anda menggunakan Postgres 9.4 atau lebih baru pertimbangkan untuk
jsonb
menggunakannyajson
.sumber
Bayangkan Anda keluar dengan sekelompok teman dan percakapan berubah menjadi film. Seseorang bertanya, "Apa pendapatmu tentang 'The Three Musketeers'?" Anda menjawab, "Yang mana?"
Informasi tambahan apa yang Anda perlukan untuk benar-benar yakin bahwa Anda berdua memikirkan film yang sama? Nama direktur? Studio produksi? Tahun dirilis? Salah satu nama bintang itu? Kombinasi dua atau lebih?
Jawaban atas pertanyaan saya dan pertanyaan Anda sama.
Namun, saya tidak akan berpikir bahwa genre akan menjadi kandidat yang baik. Salah satu alasannya, genre adalah kriteria yang terlalu subyektif. Apakah 'The Three Musketeers' action? drama? petualangan? komedi? aksi petualangan? komedi romantis? Saya sering melihat film yang sama terdaftar di bawah genre yang berbeda. Bahkan ketika Anda mengizinkan beberapa genre, pengguna Anda dapat memilih yang sepenuhnya berbeda yang tidak terdaftar dengan film aktual yang mereka cari.
Bahkan runtimes dapat berbeda, terutama antara versi teater dan VCR / DVD / b-ray.
Jadi Anda perlu atribut yang keras dan objektif yang tidak akan berubah dari satu rilis media ke yang lainnya. Sayangnya, itu dapat mengecualikan nama film karena film telah dikenal untuk diganti namanya, terutama setelah rilis sekuel.
Bagaimana dengan tanggal rilis? Rilis teater tahun 1993? Rilis VCR tahun 1999? Rilis DVD tahun 2004? Anda mendapatkan idenya.
Kalau dipikir-pikir, bagaimana dengan semua film yang disutradarai oleh Alan Smithee? Pernahkah sutradara yang sesungguhnya akhirnya melangkah maju untuk memasukkan namanya pada proyek setelah fakta? Saya tidak tahu
Hmm, lebih baik aku berhenti sementara masih ada beberapa kriteria yang tersisa.
Beberapa poin tambahan:
sumber
Kolom ID tidak memiliki keuntungan sama sekali dalam hal keunikan yang ingin / perlu Anda lakukan. Keunikan kombinasi atribut apa pun tidak akan pernah ditegakkan dengan menambahkan ID yang tidak berarti. "Keuntungannya" hanya menunjukkan ketika Anda sampai ke titik di mana Anda akan membutuhkan tabel baru yang memerlukan kunci asing untuk yang satu ini. Dalam hal ini, dan JIKA Anda telah memasukkan Id, maka Anda dapat menggunakannya sebagai FK di tabel baru Anda. (Tapi jangan berpikir itu akan menjadi makan siang gratis. Kelemahan dari pendekatan semacam itu adalah Anda mungkin akan menemukan diri Anda menulis lebih banyak untuk tujuan sekadar mengambil informasi yang bisa saja menjadi bagian dari tabel baru yang Anda buat. )
sumber