Apakah kolom ID Unik diperlukan dalam tabel banyak-ke-banyak (persimpangan)?

22

Mendapatkan beberapa proyek dimulai dengan EF, tapi aku punya beberapa pertanyaan tentang bergabung meja dan kunci dll Katakanlah saya punya tabel aplikasi dan meja perizinan. Aplikasi memiliki banyak izin dan setiap izin dapat menjadi milik banyak aplikasi (banyak-ke-banyak).

Sekarang, tabel Aplikasi dan Izin mudah:

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

Tapi apa cara TERBAIK untuk melakukan tabel bergabung? Saya punya dua opsi ini:

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

ATAU

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

Pernahkah Anda dibakar melakukannya satu arah dari yang lain? apakah ini semata-mata preferensi? Terpikir oleh saya bahwa banyak "perbedaan" akan diabstraksi oleh pola repositori saya (misalnya, saya hampir tidak akan pernah membuat seluruh objek izin dan menambahkannya ke aplikasi, tetapi melakukannya dengan ID atau nama unik atau sesuatu), tapi kurasa aku sedang mencari cerita horor, entah bagaimana.

solidau
sumber

Jawaban:

20

Saya percaya maksud Anda tabel "persimpangan", bukan "bergabung" tabel.

Tidak perlu tabel persimpangan untuk memiliki bidang ID sendiri. Anda tidak perlu bergabung atau memfilter pada ID semacam itu. Anda hanya akan bergabung atau memfilter pada ID dari tabel yang Anda pemetaan. ID pada tabel persimpangan adalah pemborosan ruang disk.

Jadi opsi "terbaik" adalah menghindari ID. Biasanya tabel persimpangan akan memiliki 2 indeks yang meliputi. Setiap indeks penutup menggunakan salah satu ID yang dipetakan sebagai bidang pengurutan primer.

Tapi "yang terbaik" bukanlah jalan panjang. Ini adalah masalah yang sangat kecil untuk memiliki bidang ID yang berlebihan. Anda tidak akan memiliki cerita horor dalam jumlah kecil disk yang terbuang. ID tidak akan "mencuri" indeks berkerumun karena Anda tidak ingin mengelompokkan pada kombo yang dipetakan.

Jika kerangka kerja Anda ingin semua tabel memiliki ID, maka lakukan. Jika standar database tim Anda menentukan semua tabel harus memiliki ID, maka lakukanlah. Jika tidak, maka hindarilah.

mike30
sumber
2
Nah, Anda sudah menyatakan bahwa menambahkan ID adalah konsesi kecil, mudah diatasi dengan potensi manfaat, jadi bagi saya tampaknya (mengingat bahwa memiliki ID unik di setiap tabel adalah praktik terbaik atau kurang di sebagian besar DBMS dan ORM) Anda akan menganjurkan memiliki ID sebagai opsi "terbaik" atau "default", daripada tidak memilikinya.
Robert Harvey
4
"Anda tidak perlu bergabung atau menanyakan ID seperti itu" - mengatakan "tidak pernah" dalam situasi teknologi mengundang hal itu terjadi. Mengatakan itu, ada saat - saat ketika Anda akan bergabung dengan tabel bergabung itu (ya, saya pernah mendengarnya disebut sebagai tabel "bergabung" lebih dari tabel "persimpangan") ke tabel keempat karena entitas yang bergabung sebenarnya adalah sebuah objek bisnis mereka sendiri.
Jesse C. Slicer
4
@RobertHarvey. ID adalah praktik yang baik untuk entitas. Tapi persimpangan lebih merupakan detail implementasi untuk banyak-banyak hubungan, bukan entitas dalam haknya sendiri. Tapi seperti yang ditunjukkan Jesse C. slider, ada kasus-kasus dimana persimpangan dapat dianggap sebagai entitas bisnis.
mike30
1
"Buang ruang disk." - Saya pikir beberapa mesin (InnoDB?) Buat kunci primer (internal) jika Anda tidak membuatnya sendiri - jadi Anda mungkin tidak benar-benar mendapatkan ruang disk dengan tidak memilikinya.
Alex
@Alex. Anda menempatkan PK komposit pada ID yang dipetakan.
mike30
11

Selama bertahun-tahun saya terbiasa memberi setiap tabel "TableName" kunci primer otomatis yang dihasilkan "TableNameID", tanpa pengecualian, bahkan untuk tabel persimpangan. Saya dapat mengatakan saya tidak pernah menyesalinya, karena itu membuat banyak hal lebih mudah ketika membuat kode generik yang melakukan sesuatu untuk "semua tabel" atau "beberapa tabel", atau untuk "banyak baris dari beberapa tabel yang berbeda".

Misalnya, jika seseorang meminta Anda untuk menyimpan beberapa baris tabel yang berbeda (atau referensi ke mereka) dalam file atau dalam memori, misalnya, untuk keperluan logging, sangat berguna ketika Anda tahu sebelumnya bahwa Anda hanya perlu menyimpan satu saja nama tabel & persis satu ID integer, dan Anda tidak harus berurusan dengan "kasus khusus".

Hal lain, ketika Anda mulai dengan PK gabungan, Anda mungkin akan beberapa kali kemudian bertemu dengan kebutuhan untuk kunci asing gabungan (karena Anda mungkin sampai pada titik di mana Anda ingin menambahkan referensi FK ke ApplicationPermissionsmeja Anda ). Maka persyaratan berikutnya mungkin untuk memiliki FK ini menjadi unik dalam hubungannya dengan atribut lain atau kunci asing - yang akan menghasilkan peningkatan kompleksitas secara keseluruhan. Tidak ada yang tidak mungkin ditangani untuk sebagian besar sistem DB modern, tentu saja, tetapi solusi yang seragam membuat hidup para programmer seringkali jauh lebih mudah.

Dan akhirnya, pernyataan seperti SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)berfungsi dengan baik dengan satu kolom sebagai kunci utama, tapi saya belum pernah melihat dialek SQL sejauh ini yang memungkinkan Anda melakukan ini dengan tombol gabungan. Jika Anda tahu sebelumnya bahwa Anda tidak akan pernah membutuhkan pertanyaan seperti ini, baiklah, tetapi jangan kaget jika besok Anda mendapatkan persyaratan yang akan paling mudah diselesaikan dengan SQL jenis ini.

Tentu saja, ketika Anda mengharapkan ApplicationPermissionsmeja Anda menampung beberapa ratus juta baris, maka Anda harus mempertimbangkan untuk menghindari sesuatu seperti a ApplicationPermissionsID.

Doc Brown
sumber
Meskipun akhirnya aku tidak memilih jawabanmu. Saya suka aspek itu. Terima kasih atas pemikiran Anda (upvote).
solidau
6

Meskipun jawaban Mike baik, berikut adalah alasan saya akan menambahkan bidang ID terpisah atau tidak.

  1. Pertimbangkan untuk menggunakan bidang ID terpisah untuk tabel persimpangan / gabung jika berisi bidang selain ID . Ini cenderung mencatat bahwa itu adalah entitas kelas satu.

  2. Pertimbangkan untuk menggunakan bidang ID terpisah jika API atau logika apa pun yang ada cenderung menggunakan bidang tunggal untuk mengambil / mengedit entitas. Itu dapat membantu orang lain mengikuti kode Anda dalam konteks proyek yang lebih besar.

  3. Jangan menggunakannya jika tidak ada manfaat khusus (KISS). EF tahu bagaimana menangani jenis tabel ini dan batasan unik komposit terkadang dapat dilewatkan ketika orang lain mencoba memahami jenis hubungan ini. Juga, ketika normalisasi saya mencoba menggunakan kunci sekecil mungkin yang secara unik mendefinisikan tuple . Dalam contoh kedua Anda, Anda secara efektif memiliki 2 kunci utama kandidat yang terpisah.

Zachary Yates
sumber
-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

Ingatlah untuk membuat indeks dan kunci asing pada keduanya PersonIddan AddressId.

Tidak peduli apa yang orang lain pikirkan "lebih baik" atau "Anda harus", ini adalah cara paling sederhana dan termudah untuk memungkinkan database berfungsi dengan baik.

16PlusYearsAsADeveloper
sumber
1
Saya pikir satu masalah dengan pendekatan ini adalah skema memungkinkan dua PersonAddressbaris dengan nilai yang identik PersonIddan AddressId.
Sam