Kunci utama atau indeks unik?

127

Di tempat kerja kami memiliki basis data besar dengan indeks unik, bukan kunci utama dan semua berfungsi dengan baik.

Saya merancang database baru untuk proyek baru dan saya punya dilema:

Dalam teori DB, kunci utama adalah elemen fundamental, tidak apa-apa, tetapi dalam proyek NYATA apa kelebihan dan kekurangan keduanya?

Apa yang Anda gunakan dalam proyek?

EDIT: ... dan bagaimana dengan kunci primer dan replikasi pada MS SQL server?

Cicik
sumber
2
Ada beberapa pertimbangan tambahan yang dibahas di sini (meskipun dengan konteks tambahan dari indeks penutup) - dba.stackexchange.com/questions/21554/…
StuartLC
CATATAN: SQLite berbeda karena mereka mengizinkan kunci utama menjadi nol, terhadap standar umum karena masalah warisan. sqlite.org/lang_createtable.html
bitinn

Jawaban:

168

Apa itu indeks unik?

Indeks unik pada kolom adalah indeks pada kolom itu yang juga memberlakukan batasan bahwa Anda tidak dapat memiliki dua nilai yang sama di kolom itu dalam dua baris yang berbeda. Contoh:

CREATE TABLE table1 (foo int, bar int);
BUAT INDEK UNIK ux_table1_foo ON table1 (foo); - Buat indeks unik di foo.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- BAIK
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- BAIK
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- BAIK
INSERT INTO table1 (foo, bar) VALUES (1, 4); - Gagal!

Entri duplikat '1' untuk kunci 'ux_table1_foo'

Sisipan terakhir gagal karena melanggar indeks unik pada kolom fooketika mencoba memasukkan nilai 1 ke dalam kolom ini untuk kedua kalinya.

Di MySQL, kendala unik memungkinkan banyak NULL.

Dimungkinkan untuk membuat indeks unik pada kolom mutiple.

Kunci utama versus indeks unik

Hal-hal yang sama:

  • Kunci utama menyiratkan indeks unik.

Hal-hal yang berbeda:

  • Kunci utama juga menyiratkan TIDAK NULL, tetapi indeks unik dapat dibatalkan.
  • Hanya ada satu kunci utama, tetapi ada beberapa indeks unik.
  • Jika tidak ada indeks berkerumun ditentukan maka kunci utama akan menjadi indeks berkerumun.
Mark Byers
sumber
4
Perhatikan bahwa indeks unik adalah indeks pada kolom tidak sepenuhnya akurat karena satu indeks unik atau kunci utama dapat mencakup lebih dari satu kolom.
Alex Jasmin
2
@Alexandre Jasmin: Memperbaiki terima kasih. Bagian tentang beberapa kolom disebutkan kemudian.
Mark Byers
Dengan mengacu pada nulls, standar ansi memungkinkan beberapa nilai null dalam set data dengan batasan unik di atasnya, dan itu juga implementasi pada Oracle dan PostgreSQL. Saya percaya bahwa SQL Server hanya memungkinkan satu nilai nol.
David Aldridge
3
tapi tetap saja saya tidak mengerti, seperti kapan harus menggunakan kunci primer atau kapan harus menggunakan indeks unik? atau mungkin keduanya di situasi yang sama.
Amit
33

Anda bisa melihatnya seperti ini:

Kunci Utama IS Unik

Nilai unik tidak harus berupa Representasi Elemen

Berarti?; Yah kunci utama digunakan untuk mengidentifikasi elemen, jika Anda memiliki "Orang" Anda ingin memiliki Nomor Identifikasi Pribadi (SSN atau semacamnya) yang merupakan Primer untuk Orang Anda.

Di sisi lain, orang tersebut mungkin memiliki e-mail yang unik, tetapi tidak mengidentifikasi orang tersebut.

Saya selalu memiliki Kunci Utama, bahkan di tabel hubungan (tabel tengah / koneksi) saya mungkin memilikinya. Mengapa? Yah saya suka mengikuti standar ketika coding, jika "Orang" memiliki pengidentifikasi, Mobil memiliki pengenal, well, maka Orang -> Mobil harus memiliki pengidentifikasi juga!

Filip Ekberg
sumber
Dalam tabel hubungan Anda: apakah maksud Anda Anda memperkenalkan kolom baru dengan kunci primer buatan (bilangan bulat misalnya) atau apakah Anda menggunakan kunci primer yang dikomposisikan (person_id, car_id)?
3
kunci utama (person_id, car_id) akan menjadi yang terbaik. Tetapi saya biasanya membuat kolom baru, tentu itu memberi beberapa overhead tetapi saya telah menganggapnya baik. Anda tidak pernah tahu apakah Anda ingin berhubungan dengan hubungan tertentu dalam skenario nanti.
Filip Ekberg
1
Hal lain yang dilakukan kunci primer pengganti untuk tabel gabungan / gabungan Anda adalah kemudahan pemeliharaan tugas manual.
Robert C. Barth
2
Anda hanya perlu kunci utama jika ingin memiliki anak. Mengapa menambahkan kolom dan urutan jika nilainya tidak muncul, jika nilainya tidak digunakan? Ini adalah pekerjaan untuk menghentikan akses dari meminta PK. Buat PK jika Anda perlu mengidentifikasi catatan pada anak, jika tidak maka akan sia-sia.
3
Jika tidak ada hubungannya dengan hubungan, apa hubungannya dengan hubungan? Anda menunjuk ke suatu bidang dan berkata, itu yang utama. Dan? Lalu apa yang terjadi? Dan jika tidak ada pk alami, saya menambahkan kolom dan urutan dan pemicu dan semuanya karena ____? Beberapa hanya perlu menjadi Pratama. Saya menghindari aturan tanpa alasan.
10

Kunci asing berfungsi dengan batasan unik serta kunci primer. Dari Buku Online:

Batasan KUNCI ASING tidak harus dikaitkan hanya dengan batasan KUNCI UTAMA di tabel lain; itu juga dapat didefinisikan untuk referensi kolom dari batasan UNIK di tabel lain

Untuk replikasi transaksional, Anda memerlukan kunci utama. Dari Buku Online:

Tabel yang diterbitkan untuk replikasi transaksional harus memiliki kunci utama. Jika tabel dalam publikasi replikasi transaksional, Anda tidak dapat menonaktifkan indeks yang terkait dengan kolom kunci utama. Indeks ini diperlukan oleh replikasi. Untuk menonaktifkan indeks, Anda harus terlebih dahulu menjatuhkan tabel dari publikasi.

Kedua jawaban untuk SQL Server 2005.

Jonas Lincoln
sumber
ITU membuatku takut (kutipan pertama). Mengapa? Saya memiliki tabel orang dengan ID sewenang-wenang yang merupakan PK saya, tetapi saya memutuskan untuk menambahkan Inggris ke Telepon, Email, & SSN ... jadi sekarang 4 tabel berbeda bergabung dengan orang di 4 kolom berbeda? Saya pikir saya akan melupakan fleksibilitas yang mungkin Anda dapatkan untuk konsistensi.
5

Pilihan kapan harus menggunakan kunci primer pengganti sebagai pengganti kunci alami itu rumit. Jawaban seperti, selalu atau tidak pernah, jarang bermanfaat. Saya menemukan bahwa itu tergantung pada situasinya.

Sebagai contoh, saya memiliki tabel berikut:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Kami memiliki dua tabel entitas ( toll_boothsdan cars) dan tabel transaksi ( drive_through). The toll_boothmeja menggunakan kunci pengganti karena tidak memiliki atribut alam yang tidak dijamin perubahan (nama dapat dengan mudah diubah). The carsmeja menggunakan kunci utama alami karena memiliki pengenal non-berubah unik ( vin). Itudrive_through tabel transaksi menggunakan kunci pengganti untuk memudahkan identifikasi, tetapi juga memiliki kendala yang unik pada atribut yang dijamin untuk menjadi unik pada saat catatan dimasukkan.

http://database-programmer.blogspot.com memiliki beberapa artikel bagus tentang topik ini.

aekeus
sumber
4

Tidak ada kerugian dari kunci primer.

Untuk menambahkan hanya beberapa informasi ke @MrWiggles dan @Peter Parker menjawab, ketika tabel tidak memiliki kunci utama misalnya Anda tidak akan dapat mengedit data dalam beberapa aplikasi (mereka akan berakhir dengan mengatakan bahwa seperti tidak dapat mengedit / menghapus data tanpa kunci utama). Postgresql memungkinkan beberapa nilai NULL berada di kolom UNIK, KUNCI UTAMA tidak mengizinkan NULL. Juga beberapa ORM yang menghasilkan kode mungkin memiliki beberapa masalah dengan tabel tanpa kunci primer.

MEMPERBARUI:

Sejauh yang saya tahu tidak mungkin untuk mereplikasi tabel tanpa kunci primer di MSSQL, setidaknya tanpa masalah ( detail ).

empi
sumber
Ada overhead saat baris baru dimasukkan atau kolom itu diperbarui.
3

Jika ada sesuatu yang merupakan kunci utama, tergantung pada mesin DB Anda, seluruh tabel akan diurutkan berdasarkan kunci primer. Ini berarti bahwa pencarian jauh lebih cepat pada kunci utama karena tidak harus melakukan dereferencing karena harus dilakukan dengan jenis indeks lainnya. Selain itu, itu hanya teori.

Ray Hidayat
sumber
3
tabel akan diurutkan berdasarkan indeks yang dikelompokkan tidak perlu oleh kunci utama.
Ray Booysen
1
Kebetulan sebagian besar orang menetapkan kunci utama mereka untuk menjadi indeks berkerumun.
Ray Booysen
Yang kita tahu adalah sering Ide benar-benar buruk, kecuali kita seperti hot-spot dan pohon indeks tidak seimbang di meja kami, tentu saja ...
Mike Woodhouse
1
Bukan SELALU Ide yang Benar-Benar Buruk. Ketahui data Anda, ketahui RDBMS Anda, ketahuilah apa artinya pilihan. Jarang pilihan SELALU baik atau buruk. Jika SELALU satu, database akan mengamanatkan atau melarangnya. Mereka memberi Anda pilihan karena 'Itu Tergantung.'
2

Selain apa yang dikatakan jawaban lain, beberapa basis data dan sistem mungkin memerlukan yang utama untuk hadir. Satu situasi muncul di pikiran; ketika menggunakan replikasi perusahaan dengan Informix, seorang PK harus hadir untuk sebuah tabel untuk berpartisipasi dalam replikasi.

tddmonkey
sumber
2

Selama Anda tidak mengizinkan NULL untuk suatu nilai, mereka harus ditangani sama, tetapi nilai NULL ditangani secara berbeda pada basis data (AFAIK MS-SQL tidak mengizinkan lebih dari satu (1) Nilai NULL, mySQL dan Oracle memungkinkan ini , jika sebuah kolom UNIK) Maka Anda harus mendefinisikan kolom ini BUKAN NULL UNIK INDEKS

Peter Parker
sumber
1
MS-SQL memungkinkan beberapa nilai NULL dalam kolom yang memiliki indeks unik, sebagaimana seharusnya setiap RDBMS. Pikirkan seperti ini: NULL bukan nilai, jadi ketika Anda memasukkan NULL kedua, itu tidak akan pernah cocok dengan yang sudah ada. Ekspresi (NULL == NULL) tidak evalute ke true atau false, itu mengevaluasi ke NULL.
gregmac
thanx gregmac, saya tidak yakin, apakah MS mengikuti ini. Saya ingat beberapa MS Quirks dengan ini, namun beberapa tahun yang lalu (pra 2000) dan juga bisa menjadi batuk
Peter Parker
2

Tidak ada yang namanya kunci utama dalam teori data relasional, jadi pertanyaan Anda harus dijawab pada tingkat praktis.

Indeks unik bukan bagian dari standar SQL. Implementasi tertentu dari DBMS akan menentukan apa konsekuensi dari mendeklarasikan indeks unik.

Di Oracle, mendeklarasikan kunci utama akan menghasilkan indeks unik yang dibuat atas nama Anda, jadi pertanyaannya hampir bisa diperdebatkan. Saya tidak bisa memberi tahu Anda tentang produk DBMS lainnya.

Saya lebih suka mendeklarasikan kunci utama. Ini memiliki efek melarang NULL di kolom kunci dan juga melarang duplikat. Saya juga lebih suka menyatakan batasan REFERENSI untuk menegakkan integritas entitas. Dalam banyak kasus, menyatakan indeks pada coulmn (s) kunci asing akan mempercepat bergabung. Jenis indeks ini secara umum tidak boleh unik.

Walter Mitty
sumber
Kunci utama dalam MS SQL Server selalu UNIK dan BUKAN NULL - misalnya itu benar-benar hanya indeks Unik, tetapi dengan batasan tambahan bahwa itu tidak boleh NULL.
marc_s
Oracle dapat menerapkan Batasan Unik dengan indeks tidak unik. Saya akan terkejut jika MSSS tidak bisa. Mengatakan "itu benar-benar hanya indeks unik" adalah tindakan merugikan.
"Dalam banyak kasus, menyatakan indeks pada coulmn (s) kunci asing akan mempercepat bergabung." ini hampir selalu tidak benar dalam dunia pergudangan data di mana hash bergabung akan lebih disukai jika tersedia.
JAC2703
OP tidak menyebutkan gudang. Saya tidak yakin bagaimana hash loins bekerja di server sql. Berapa banyak pekerjaan yang dapat dilakukan pada waktu pembaruan gudang.
Walter Mitty
2

Ada beberapa kelemahan dari INDEKS BERGERAK vs INDEKS UNIK.

Seperti yang sudah dinyatakan, INDEKS BERKELILINGAN secara fisik memesan data dalam tabel.

Ini berarti bahwa ketika Anda memiliki banyak jika menyisipkan atau menghapus tabel yang berisi indeks berkerumun, setiap kali (well, hampir, tergantung pada faktor pengisian Anda) Anda mengubah data, tabel fisik perlu diperbarui untuk tetap diurutkan.

Dalam tabel yang relatif kecil, ini bagus, tetapi ketika sampai ke tabel yang memiliki nilai data GB, dan memasukkan / menghapus mempengaruhi penyortiran, Anda akan mengalami masalah.

Nico Bester
sumber
Apa untungnya? kueri yang disortir lebih cepat? apakah ini lebih baik untuk kasus penggunaan ketika Anda menulis sebagian besar data Anda sekali (atau jarang) dan menanyakannya sepanjang waktu?
Buffalo
1

Saya hampir tidak pernah membuat tabel tanpa kunci primer numerik. Jika ada juga kunci alami yang harus unik, saya juga meletakkan indeks unik di atasnya. Gabungan lebih cepat pada bilangan bulat daripada kunci alam multikolom, data hanya perlu berubah di satu tempat (kunci alami cenderung perlu diperbarui yang merupakan hal buruk ketika berada di kunci primer - hubungan kunci asing). Jika Anda akan membutuhkan replikasi, gunakan GUID alih-alih bilangan bulat, tetapi sebagian besar saya lebih suka kunci yang dapat dibaca pengguna terutama jika mereka perlu melihatnya untuk membedakan antara John Smith dan John Smith.

Beberapa kali saya tidak membuat kunci pengganti adalah ketika saya memiliki tabel bergabung yang terlibat dalam hubungan banyak ke banyak. Dalam hal ini saya menyatakan kedua bidang sebagai kunci utama.

HLGEM
sumber
“Saya hampir tidak pernah membuat tabel tanpa kunci primer numerik”: mengapa selalu numerik? Kunci primer tidak harus berupa angka (tidak harus berupa AUTO_INCREMENT).
Hibou57
@ Hinou57, karena saya telah menemukan bahwa kunci alami jarang sebenarnya unik dan hampir selalu dapat diubah. Selanjutnya bergabung pada intergers umumnya jauh lebih cepat daripada bergabung pada kunci alami varcahrr atau kunci komposit yang lebih buruk. Saya tidak akan menggunakannya paling sering. Ini mungkin berbeda untuk jenis informasi yang Anda simpan di database Anda, tetapi dalam pengalaman pribadi saya, saya telah menemukan kunci alami menjadi sangat tidak dapat diandalkan dari waktu ke waktu.
HLGEM
Terima kasih atas balasannya HLGEM. Apa maksudmu dengan tidak bisa diandalkan? Performa? (Saya harap itu bukan masalah reliabilitas dalam arti integritas data). Saya sedikit terkejut dengan kata-kata Anda, karena saya menggunakan kunci integer atau kunci yang lebih alami seperti VARCHAR pendek, kemungkinan akan membuat perbedaan kecil karena hashing digunakan di mana-mana bahkan dengan mesin DB paling sederhana.
Hibou57
Mereka tidak dapat diandalkan dalam banyak kasus karena mereka tidak unik andal meskipun mereka seharusnya. Mereka tidak dapat diandalkan karena mereka berubah dan yang dapat mempengaruhi jutaan catatan dalam uopdate. Ini adalah pengalaman saya setelah melihat dan mengelola atau menanyakan data dari atau mengimpor data dari ratusan basis data yang menyimpan data tentang berbagai jenis informasi yang berbeda.
HLGEM
1

Pemahaman saya adalah bahwa kunci utama dan indeks unik dengan batasan bukan-nol, adalah sama (*); dan saya kira satu memilih satu atau yang lain tergantung pada apa spesifikasi secara eksplisit menyatakan atau menyiratkan (masalah apa yang ingin Anda ungkapkan dan secara tegas menegakkan). Jika memerlukan keunikan dan bukan-null, maka jadikan itu kunci utama. Jika itu hanya terjadi, semua bagian dari indeks unik tidak-nol tanpa persyaratan untuk itu, maka buat saja itu indeks unik.

Satu-satunya perbedaan yang tersisa adalah, Anda mungkin memiliki beberapa indeks unik bukan nol, sementara Anda tidak dapat memiliki beberapa kunci utama.

(*) Kecuali perbedaan praktis: kunci primer dapat menjadi kunci unik default untuk beberapa operasi, seperti mendefinisikan kunci asing. Ex. jika seseorang mendefinisikan kunci asing yang merujuk pada tabel dan tidak memberikan nama kolom, jika tabel yang direferensikan memiliki kunci utama, maka kunci utama akan menjadi kolom yang direferensikan. Kalau tidak, kolom yang direferensikan harus diberi nama secara eksplisit.

Yang lain di sini menyebutkan replikasi DB, tapi saya tidak tahu.

Hibou57
sumber
0

Indeks Unik dapat memiliki satu nilai NULL. Ini menciptakan INDEKS NON-CLUSTERED. Kunci Utama tidak boleh berisi nilai NULL. Ini menciptakan INDEKS BERKELAS.

Chirag
sumber
0

Dalam MSSQL, kunci primer harus meningkat secara monoton untuk kinerja terbaik pada indeks berkerumun. Oleh karena itu bilangan bulat dengan penyisipan identitas lebih baik daripada kunci alami yang mungkin tidak meningkat secara monoton.

Markus
sumber
-1

Jika itu terserah saya ...

Anda harus memenuhi persyaratan database dan aplikasi Anda.

Menambahkan bilangan bulat penambahan otomatis atau kolom id panjang ke setiap tabel untuk berfungsi sebagai kunci utama menangani persyaratan basis data.

Anda kemudian akan menambahkan setidaknya satu indeks unik lainnya ke tabel untuk digunakan oleh aplikasi Anda. Ini akan menjadi indeks pada employee_id, atau account_id, atau customer_id, dll. Jika memungkinkan, indeks ini tidak boleh menjadi indeks komposit.

Saya lebih suka indeks pada beberapa bidang secara individual daripada indeks komposit. Basis data akan menggunakan indeks bidang tunggal setiap kali klausa mana menyertakan bidang itu, tetapi hanya akan menggunakan komposit saat Anda memberikan bidang dalam urutan yang benar - artinya itu tidak dapat menggunakan bidang kedua dalam indeks komposit kecuali jika Anda memberikan baik yang pertama dan kedua di mana Anda klausa.

Saya semua menggunakan indeks tipe Fungsi yang dihitung atau - dan akan merekomendasikan menggunakannya lebih dari indeks komposit. Itu membuatnya sangat mudah untuk menggunakan indeks fungsi dengan menggunakan fungsi yang sama di klausa tempat Anda.

Ini menangani persyaratan aplikasi Anda.

Sangat mungkin bahwa indeks non-primer lainnya sebenarnya memetakan nilai kunci indeks itu ke nilai kunci primer, bukan rowid (). Ini memungkinkan operasi penyortiran fisik dan penghapusan terjadi tanpa harus membuat ulang indeks ini.

Rodney P. Barbati
sumber