Praktik buruk Foreign Key yang tidak dapat dibatalkan?

114

Katakanlah Anda memiliki tabel Pesanan dengan kunci asing ke Id Pelanggan. Sekarang, misalkan Anda ingin menambahkan Pesanan tanpa Id Pelanggan, (apakah itu mungkin adalah pertanyaan lain) Anda harus membuat kunci asing NULL ... Apakah itu praktik yang buruk atau Anda lebih suka bekerja dengan tabel tautan antara Pesanan dan Pelanggan? Meskipun hubungannya adalah 1 ke n, tabel tautan akan membuatnya menjadi n ke n. Di sisi lain, dengan tabel tautan, saya tidak memiliki NULLS itu lagi ...

Sebenarnya tidak akan ada banyak NULL dalam database, karena record dengan foreign key ke NULL hanya sementara sampai pelanggan untuk pesanan ditambahkan.

(Dalam kasus saya, ini bukan Pesanan dan Pelanggan).

EDIT: Bagaimana dengan Pelanggan yang belum ditetapkan untuk ditautkan?

Lieven Cardoen
sumber
9
Itu IS salah satu tujuan utama memiliki NULL tersedia dalam skema database. Lebih lanjut, itulah mengapa Anda dapat mendeklarasikan field NULL atau NOT NULL, sehingga persyaratan khusus skema Anda dapat dipenuhi.
gahooa
7
Saya awalnya membaca pertanyaan itu sebagai kunci Primer Nullable , dan akan menjelaskan dengan beberapa nasihat kuat ... :-)
Andrzej Doyle

Jawaban:

51

Memiliki tabel tautan mungkin merupakan pilihan yang lebih baik. Setidaknya itu tidak melanggar normalisasi BCNF (bentuk normal Boyce-Codd). namun saya lebih suka bersikap pragmatis. Jika Anda memiliki sangat sedikit dari nilai nol ini dan hanya sementara, saya pikir Anda harus melewati tabel tautan karena hanya menambah kompleksitas pada skema.

Di samping catatan; menggunakan tabel tautan tidak selalu membuatnya menjadi n menjadi n, jika Anda dalam tabel tautan menggunakan kunci asing yang menunjuk ke tabel pesanan Anda sebagai kunci utama dalam tabel tautan itu hubungannya masih 1..n. Hanya boleh ada satu entri di tabel tautan itu per pesanan.

Patrik Hägne
sumber
2
source__destination_link atau SourceDestination
Svisstack
7
Saya tertarik untuk mendengar tentang situasi ketika memiliki tabel tautan lebih baik, saya tidak pernah mengalami situasi di mana itu akan meningkatkan aliran proses dengan cara apa pun.
Reimius
5
Seperti yang ditunjukkan dalam jawaban saya, saya akan bersikap pragmatis dalam kasus khusus ini dan tidak menggunakan tabel tautan. Saya yakin formulir normal tidak diciptakan untuk meningkatkan aliran proses melainkan untuk memastikan konsistensi dan untuk menghindari redundansi. Ini adalah diskusi yang sangat umum, saya pikir itu harus dilihat dari kasus ke kasus.
Patrik Hägne
110

Tidak Tidak ada yang salah dengan Nullable FKs. Hal ini umum terjadi ketika entitas yang ditunjuk FK berada dalam hubungan (nol atau satu) hingga (1 atau banyak) dengan tabel referensi Kunci utama.

Contohnya mungkin jika Anda memiliki alamat fisik dan atribut alamat surat (kolom) dalam tabel, dengan FK ke tabel alamat. Anda dapat membuat alamat fisik nullable untuk ditangani saat entitas hanya memiliki kotak pos (alamat surat), dan alamat surat yang tidak dapat ditangani jika alamat surat sama dengan alamat fisik (atau tidak).

Charles Bretana
sumber
39

Kolom nullable bisa di 1NF sampai 5NF, tapi tidak di 6NF menurut yang saya baca.

Hanya jika Anda tahu lebih baik daripada Chris Date "apa arti sebenarnya dari bentuk normal pertama". Jika x dan y keduanya nihil, dan memang di beberapa baris x dan y keduanya null, maka WHERE x=ytidak menghasilkan true. Ini membuktikan tanpa keraguan bahwa nol bukanlah nilai (karena nilai riil selalu sama dengan dirinya sendiri). Dan karena RM menetapkan bahwa "harus ada nilai di setiap sel tabel", apa pun yang mungkin berisi null, bukanlah hal yang berhubungan, dan dengan demikian pertanyaan tentang 1NF bahkan tidak muncul.

Saya pernah mendengarnya berpendapat bahwa kolom Nullable secara umum mematahkan derajat pertama normalisasi.

Lihat di atas untuk alasan kuat yang mendasari argumen itu.

Tapi dalam prakteknya sangat praktis.

Hanya jika Anda kebal terhadap sakit kepala yang biasanya terjadi di seluruh dunia. Salah satu sakit kepala seperti itu (dan ini hanya masalah kecil, dibandingkan dengan nullfenomena lain ) adalah kenyataan bahwa WHERE x=ydalam SQL sebenarnya berarti WHERE x is not null and y is not null and x=y, tetapi sebagian besar programmer tidak menyadari fakta itu dan hanya membacanya. Kadang-kadang tanpa bahaya, di lain waktu tidak.

Faktanya, kolom nullable melanggar salah satu aturan desain database paling mendasar: jangan gabungkan elemen informasi yang berbeda dalam satu kolom. Null melakukan hal itu karena menggabungkan nilai boolean "kolom ini adalah / tidak benar-benar ada" dengan nilai sebenarnya.

Erwin Smout
sumber
18
1 untuk "DI MANA x bukan nol dan y bukan nol dan x = y". Tidak menyadarinya.
RobM
1
Argumen dan contoh yang ditata dengan sangat baik.
pedz
1
Satu masalah. Ketika nilai "tidak ada" (Yang ADALAH skenario dunia nyata), dan atribut database tidak mengizinkan null, nilai apa pun yang ada di atribut adalah SALAH. Mengenai sakit kepala, ingat, KISS, itu tidak hanya berarti membuatnya tetap sederhana, itu berarti Menjaga sesederhana mungkin, tetapi tidak lebih sederhana. Jika "model relasional" memerlukan hasil yang tidak realistis dan bodoh, maka mungkin aturan perlu diperluas untuk menangani data dunia nyata yang diperlukan?
Charles Bretana
1
Telah ditunjukkan bahwa logika tiga nilai mengarah pada kebutuhan akan logika empat nilai, dan itu mengarah pada kebutuhan akan logika lima nilai, dll. Logika bernilai 2 sudah cukup, tetapi struktur data yang kita dapatkan ketika menerapkannya menjadikan "sesederhana mungkin" masih jauh lebih sederhana daripada "sesederhana yang kita inginkan".
Erwin Smout
2
Chris Date, Logic & Databases, Chpt 6, "Why relational DBMS logic must not be many-values", hal 145. Daftar referensi ke bab tersebut juga harus menarik, terutama yang melibatkan McGoveran.
Erwin Smout
13

Saya tidak bisa melihat ada yang salah dengan itu hanya hubungan n-1 opsional yang akan diwakili dengan null di foreign-key. Jika tidak, jika Anda meletakkan tabel tautan Anda, maka Anda harus mengatur bahwa itu tidak menjadi hubungan nn, sehingga menyebabkan lebih banyak masalah.

pedromarce
sumber
2
Sebenarnya ini adalah hubungan 0-N, bukan hubungan 1-N opsional. Tapi saya setuju dengan Anda.
Eric J.
5
Mengelola? Ini adalah batasan UNIK sederhana di sisi 0-ke-1!
wqw
2
Ya, ini adalah kendala UNIK, tetapi Anda juga harus berurusan dengan kemungkinan pengecualian nanti dalam kode Anda karena kendala itu ...
pedromarce
4

Hubungan opsional pasti dimungkinkan dalam model relasional.

Anda dapat menggunakan null untuk menyatakan tidak adanya hubungan. Mereka nyaman, tetapi mereka akan menyebabkan Anda sakit kepala yang sama dengan nulls menyebabkan Anda di tempat lain. Satu tempat di mana mereka tidak menimbulkan masalah adalah bergabung. Baris yang memiliki null dalam kunci asing tidak cocok dengan baris mana pun dalam tabel yang direferensikan. Jadi mereka keluar dari gabungan dalam. Jika Anda melakukan gabungan luar, Anda akan berurusan dengan nol.

Jika Anda benar-benar ingin menghindari null (bentuk normal ke-6), Anda dapat mendekomposisi tabel. Salah satu dari dua tabel yang diuraikan memiliki dua kolom kunci asing. Salah satunya adalah kunci asing opsional yang Anda miliki, dan yang lainnya adalah kunci asing yang mereferensikan kunci utama dari tabel asli. Sekarang Anda harus menggunakan batasan untuk mencegah hubungan menjadi banyak-ke-banyak, jika Anda ingin mencegahnya.

Walter Mitty
sumber
2

Menggunakan NULL akan menjadi cara yang baik untuk membersihkan pesanan yang tidak lengkap:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Di atas akan menunjukkan pesanan yang lebih lama dari 15 menit tanpa ID pelanggan terkait.

matpie
sumber
1

Jika Anda hanya menambahkan pesanan sementara tanpa id pelanggan sampai pelanggan ditentukan, bukankah lebih mudah untuk menambahkan pelanggan dan memesan dalam satu transaksi, sehingga menghilangkan kebutuhan untuk entri kunci asing NULL dan menghindari kendala atau pemicu Anda telah mengatur untuk dilanggar?

Biasanya situasi ini muncul di aplikasi web di mana pesanan dirinci sebelum pelanggan menentukan siapa dia. Dan dalam situasi tersebut, pesanan disimpan dalam status server atau dalam cookie hingga semua status yang diperlukan untuk pesanan lengkap diberikan, dan saat itu pesanan tersebut disimpan ke database.

Kunci asing NULL baik-baik saja untuk hal-hal seperti alamat, seperti yang disebutkan di atas. Tetapi bidang pelanggan NULL tidak masuk akal untuk suatu pesanan dan harus dibatasi.

Tandai Hijau
sumber
Order-customer adalah sebagai contoh. Di aplikasi saya, ini lebih seperti alamat. Tidak dapat langsung menemukan contoh yang benar seluruhnya. Terima kasih.
Lieven Cardoen
1
Ini bisa menjadi skenario yang valid jika database digunakan untuk menyimpan item di keranjang belanja, di mana keranjang belanja bukan milik pengguna terdaftar.
Johnie Karr
1

Anda selalu dapat menambahkan baris buatan ke tabel Pelanggan Anda, seperti Id = -1 dan CustomerName = 'Unknown' dan kemudian jika Anda biasanya menetapkan CustomerId Anda di Order NULL atur ke -1.

Hal ini memungkinkan Anda untuk tidak memiliki FK yang dapat dinihilkan tetapi masih mewakili kekurangan data dengan tepat (dan akan menyelamatkan Anda dari pengguna hilir yang tidak mengetahui cara menangani NULL).

Stephen S.
sumber
Hanya untuk menambahkan ini, ingat bahwa NULLS tidak disimpan dalam indeks (dalam oracle) jadi ini berarti bahwa melewatkan tabel tautan dan menggunakan FK nullable akan masuk akal - kinerja bijaksana. Hal lain yang dapat bergantung padanya adalah jika Anda ingin menyimpan hal lain di tabel tautan ini, misalnya, SIAPA yang membuat tautan dan kapan? Apakah tautan sekarang tidak aktif / dihapus (tetapi dulu pernah?)
Layak7
Ini ide yang buruk. Jika Anda memiliki kunci asing yang disetel, dan data yang dituju kemudian dihapus, Anda tidak akan mendapatkan pengecualian kunci asing dan sekarang data Anda tidak berguna. Lebih buruk lagi, jika sesuatu yang lain kemudian ditetapkan ke kunci itu Anda menunjuk ke pelanggan yang sepenuhnya salah
IcedDante
0

FK yang tidak dapat dibatalkan untuk relasi banyak-ke-satu opsional benar-benar baik-baik saja.

Henning
sumber
-1

Saya pernah mendengarnya berpendapat bahwa kolom Nullable secara umum melanggar tingkat normalisasi pertama. Tapi dalam prakteknya sangat praktis.

Bryan McLemore
sumber
3
Kolom nullable bisa di 1NF sampai 5NF, tapi tidak di 6NF menurut yang saya baca.
Walter Mitty
-1

Ya, ada yang salah. Ini bukan kunci asing jika nullable. Desain database-nya berdasarkan kode. Mungkin Anda membuat tautan nol untuk tidak ditetapkan. atau "Unassigned" jika Anda menggunakan karakter col. Jaga integritas data Anda 100%.

danny117
sumber