Nullable Foreign Key kötü uygulama?


114

Diyelim ki bir Müşteri Kimliğine yabancı anahtarı olan bir masa Siparişleriniz var. Şimdi, Müşteri Kimliği olmadan bir Sipariş eklemek istediğinizi varsayalım (bunun mümkün olup olmadığı başka bir soru olabilir) yabancı anahtarı NULL yapmanız gerekir ... Bu kötü bir uygulama mı yoksa aradaki bağlantı tablosu ile mi çalışmayı tercih edersiniz Siparişler ve Müşteriler? İlişki 1'den n'ye olmasına rağmen, bir bağlantı tablosu onu n'den n'ye yapar. Öte yandan, bir bağlantı tablosuyla, artık bu NULL'lara sahip değilim ...

Aslında veritabanında çok fazla NULL olmayacak, çünkü NULL'a yabancı anahtar içeren bir kayıt, sipariş için bir müşteri eklenene kadar geçici olarak kalır.

(Benim durumumda bu bir Sipariş ve Müşteri değildir).

DÜZENLEME: Bağlantı kurulacak atanmamış bir Müşteri ne olacak?


9
Bu, bir veritabanı şemasında NULL'ların kullanılabilir olmasının ana amaçlarından biridir. Ayrıca, şemanızın belirli gereksinimlerinin karşılanabilmesi için alanları NULL veya NOT NULL olarak bildirebilmenizin nedeni budur.
gahooa

7
Başlangıçta soruyu Nullable Primary anahtarları olarak okudum ve bazı güçlü tavsiyelerle içeri girmek üzereydim ... :-)
Andrzej Doyle

Yanıtlar:


51

Bağlantı tablosuna sahip olmak muhtemelen daha iyi bir seçenektir. En azından normalizasyon BCNF'sini (Boyce-Codd normal formu) ihlal etmez . ancak pragmatik olmayı tercih ederim. Bu boş değerlerden çok azına sahipseniz ve bunlar sadece geçiciyse, şemaya sadece karmaşıklık kattığı için bağlantı tablosunu atlamanız gerektiğini düşünüyorum.

Bir yan not olarak; Bir bağlantı tablosunun kullanılması onu n'den n'ye yapmaz, eğer bağlantı tablosunda sipariş tablonuza işaret eden yabancı anahtarı o bağlantı tablosundaki birincil anahtar olarak kullanırsanız, ilişki hala 1..n'dir. Bu bağlantı tablosunda sipariş başına yalnızca bir giriş olabilir.


2
source__destination_link veya SourceDestination
Svisstack

7
Bir bağlantı tablosuna sahip olmanın daha iyi olduğu bir durum hakkında duymak isterim, hiçbir şekilde süreç akışını iyileştirecek bir duruma hiç rastlamadım.
Reimius

5
Cevabımda belirtildiği gibi, bu özel durumda pragmatik olurum ve bir bağlantı tablosu kullanmazdım. Eminim normal formlar süreç akışını iyileştirmek için değil, tutarlılığı sağlamak ve fazlalıktan kaçınmak için icat edilmiştir. Yine de çok genel bir tartışma, bence duruma göre ele alınması gerekiyor.
Patrik Hägne

110

Hayır Nullable FK'lerde yanlış bir şey yok. Bu, FK'nin işaret ettiği varlık birincil Anahtara başvurulan tablo ile (sıfır veya bir) ila (1 veya çok) ilişkisinde olduğunda yaygındır.

Bir örnek olarak, bir Adres tablosuna FK'leri içeren bir tabloda hem Fiziksel adresiniz hem de Posta adresi özniteliğiniz (sütun) olması olabilir. Fiziksel adresi, varlığın yalnızca bir posta kutusu (posta adresi) olduğunda işlenecek şekilde null yapılabilir ve posta adresi fiziksel adresle aynı olduğunda (veya olmadığı) işlenecek posta adresini null yapılabilir hale getirebilirsiniz.


39

Null yapılabilir sütunlar 1NF'den 5NF'ye kadar olabilir, ancak okuduğuma göre 6NF'de olmayabilir.

Sadece Chris Date'den daha iyi "ilk normal biçimin gerçekte ne anlama geldiğini" biliyorsanız. Hem x hem de y null değerine sahipse ve aslında bazı satırlarda x ve y her ikisi de ise null, o zaman WHERE x=ysonuç vermez true. Bu, boşun bir değer olmadığını makul şüphenin ötesinde kanıtlar (çünkü herhangi bir gerçek değer her zaman kendisine eşittir). RM, "bir tablonun her hücresinde bir değer olması gerektiğini" öngördüğünden, muhtemelen boş değerler içeren herhangi bir şey ilişkisel bir şey değildir ve bu nedenle 1NF sorunu ortaya çıkmaz bile.

Nullable sütunlarının genel olarak birinci normalleştirme derecesini bozduğunu duydum.

Bu argümanın altında yatan sağlam neden için yukarıya bakın.

Ama pratikte çok pratik.

Sadece dünyanın geri kalanında genellikle neden olduğu baş ağrılarına karşı bağışıksanız. Böyle bir baş ağrısı (ve diğer nullfenomenlere kıyasla sadece küçük bir sorun ), WHERE x=ySQL'de aslında anlamı olduğu WHERE x is not null and y is not null and x=y, ancak çoğu programcının bu gerçeğin farkında olmadığı ve sadece okuduğu gerçeğidir. Bazen zarar vermeden, bazen zarar vermeden.

Aslında, boş değer atanabilir sütunlar en temel veritabanı tasarım kurallarından birini ihlal eder: farklı bilgi öğelerini tek bir sütunda birleştirmeyin. Boş değerler, "bu alan gerçekten mevcut / yok" boole değerini gerçek değer ile birleştirdikleri için tam olarak bunu yapar.


18
"WHERE x null değildir ve y null değildir ve x = y" için +1. Bunun farkında değildim.
RobM

1
Argüman ve örnekler çok güzel bir şekilde ortaya kondu.
pedz

1
Bir problem. Değer "olmadığında" (ki bu gerçek dünya senaryosudur) ve veritabanı özniteliği boş değerlere izin vermediğinde, öznitelikteki değer ne olursa olsun YANLIŞ olur. Baş ağrılarına gelince, unutmayın, KISS, sadece basit tutmak anlamına gelmez, mümkün olduğunca basit tutun, ama daha basit değil anlamına gelir. "İlişkisel model" gerçekçi olmayan, aptalca bir sonuç gerektiriyorsa, o zaman belki de kuralların gerekli gerçek dünya verilerini ele almak için genişletilmesi gerekir?
Charles Bretana

1
Vs. beş değerli mantık, vb bir ihtiyaca dört değerli mantık için ihtiyaca üç değerli mantık potansiyel müşteriler ve bu potansiyel müşteriler 2 değerli mantık olduğu gösterilmiştir olduğunu , yeterli, ancak veri yapıları ne zaman almak bunu uygulamak, "olabildiğince basit" yapmaktan, "istediğimiz kadar basit" olmaktan çok daha basit hale getirir.
Erwin Smout

2
Chris Date, Logic & Databases, Bölüm 6, "İlişkisel DBMS mantığı neden çok değerli olmamalıdır", sf 145. Bu bölüme yönelik referansların listesi, özellikle McGoveran'ı içerenler de ilginç olmalıdır.
Erwin Smout

13

Yabancı anahtarda null ile temsil edilecek olan isteğe bağlı bir n-1 ilişkisi olduğu konusunda yanlış bir şey göremiyorum. Aksi takdirde, bağlantı tablonuzu koyarsanız, bunun bir nn ilişkisi haline gelmeyeceğini, dolayısıyla daha fazla soruna neden olacağını yönetmeniz gerekir.


2
Aslında bu bir 0-N ilişkisi, isteğe bağlı bir 1-N ilişkisi değil. Ama sana katılıyorum.
Eric J.

5
Yönet? 0'a 1 tarafta basit bir EŞSİZ kısıtlamadır!
wqw

2
Evet, EŞSİZ bir kısıtlamadır, ancak daha sonra bu kısıtlama nedeniyle kodunuzda olası istisnalarla da ilgilenmeniz gerekecektir ...
09:45 pedromarce

4

İlişkisel modelde isteğe bağlı ilişkiler kesinlikle mümkündür.

Bir ilişkinin olmadığını ifade etmek için null değerleri kullanabilirsiniz. Kullanışlılar, ancak boşluğun size başka yerlerde neden olduğu aynı baş ağrılarına neden olacaklar. Herhangi bir soruna neden olmadıkları bir yer birleşmektir. Yabancı anahtarda null değeri olan satırlar başvurulan tablodaki hiçbir satırla eşleşmez. Böylece iç birleşimden çıkarlar. Dış birleşimler yaparsanız, yine de sıfırlarla uğraşacaksınız.

Eğer gerçekten boş değerlerden kaçınmak istiyorsanız (6. normal biçim), tabloyu ayrıştırabilirsiniz. Ayrıştırılmış iki tablodan birinde iki yabancı anahtar sütunu var. Biri sahip olduğunuz isteğe bağlı yabancı anahtardır, diğeri ise orijinal tablonun birincil anahtarına başvuran bir yabancı anahtardır. Artık ilişkinin çoktan çoğa olmasını önlemek için kısıtlamalar kullanmanız gerekir, bunu önlemek istersiniz.


2

NULL kullanmak, eksik siparişleri temizlemek için iyi bir yol olacaktır:

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

Yukarıdakiler, ilgili müşteri kimliği olmayan 15 dakikadan daha eski siparişleri gösterir.


1

Bir müşteri tanımlanana kadar müşteri kimliği olmadan yalnızca siparişi geçici olarak ekliyorsanız, müşteriyi ve siparişi tek bir işlemde eklemek daha kolay olmaz mı, böylece NULL yabancı anahtar girişi ihtiyacını ortadan kaldırır ve herhangi bir kısıtlama veya tetikleyiciden kaçınır mı ihlal edilmeyi mi ayarladın?

Normalde bu durum, müşterinin kim olduğunu tanımlamadan önce siparişin detaylandırıldığı web uygulamalarında ortaya çıkar. Ve bu durumlarda, sipariş, eksiksiz bir sipariş için gerekli tüm durum sağlanana kadar sunucu durumunda veya bir çerezde tutulur ve bu noktada sipariş veri tabanında saklanır.

NULL yabancı anahtarlar, yukarıda belirtildiği gibi adresler gibi şeyler için uygundur. Ancak NULL müşteri alanı bir sipariş için mantıklı değildir ve sınırlandırılmalıdır.


Sipariş-müşteri örnek olarak verilmiştir. Benim uygulamamda idd daha çok adreslere benziyor. Tam olarak doğru olan bir örnek hemen bulamadım. Teşekkürler.
Lieven Cardoen

1
Veritabanı, alışveriş sepetinin kayıtlı bir kullanıcıya ait olmadığı bir alışveriş sepetindeki öğeleri depolamak için kullanılıyorsa, bu geçerli bir senaryo olabilir.
Johnie Karr

1

Müşteri tablonuza her zaman Id = -1 ve CustomerName = 'Unknown' gibi yapay bir satır ekleyebilir ve ardından normalde Order NULL'da CustomerId'inizi -1 olarak ayarlayacağınız durumlarda ekleyebilirsiniz.

Bu, boş değer atanabilir FK'lere sahip olmanıza izin vermez, ancak yine de uygun şekilde veri eksikliğini temsil eder (ve sizi NULL'larla nasıl başa çıkılacağını bilmeyen alt kullanıcılardan kurtarır).


Buna ek olarak, NULLS'nin bir dizinde (oracle'da) depolanmadığını unutmayın, bu nedenle bu, bağlantı tablosunu atlamanın ve boş değer atanabilir FK'ye gitmenin mantıklı olacağı anlamına gelir - performans açısından. Bağımlı olabileceği diğer bir şey de, bu bağlantı tablosunda başka bir şey saklamak isteyip istemediğinizdir, örneğin, bağlantıyı WHO ne zaman yaptı? Bağlantı şu anda etkin değil mi / silinmiş mi (ancak bir zamanlar öyleydi?)
Worthy7

Bu kötü bir fikir. Ayarlanmış bir yabancı anahtarınız varsa ve işaret ettiği veriler daha sonra kaldırılırsa, yabancı anahtar istisnasını almazsınız ve artık verileriniz anlamsızdır. Daha da kötüsü, başka bir şey daha sonra tamamen yanlış müşteriye işaret edip etmediğinizi tuşa atanmış açıksa
IcedDante

0

İsteğe bağlı çoktan bire ilişkiler için null atanabilir FK'ler tamamen iyidir.


-1

Genel olarak Nullable sütunların normalleştirmenin birinci derecesini kırdığını iddia ettiğini duydum. Ama pratikte çok pratik.


3
Null yapılabilir sütunlar 1NF'den 5NF'ye kadar olabilir, ancak okuduğuma göre 6NF'de olmayabilir.
Walter Mitty

-1

Evet bir sorun var. Boş verilebilirse yabancı anahtar değildir. Koda göre veritabanı tasarımı. Belki atanmamışlarla sıfır bağlantı yaparsınız. veya bir karakter col kullanıyorsanız "Atanmamış". Verilerinizin bütünlüğünü% 100 koruyun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.