Geçişli yabancı anahtarlar eklemeli miyim?


11

Basit örnek: bir müşteri tablosu var.

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

Veritabanındaki diğer tüm veriler a bağlantılıdır Customer, bu nedenle örneğin Ordersşöyle görünür:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

Şimdi aşağıdakilere bağlantı veren bir tablo olduğunu varsayalım Orders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

Ben ayrı bir yabancı anahtar eklemek gerekir Itemsiçin Customers?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

Bunun yerine bir resim: kesikli çizgi / FK mı eklemeliyim?

Basit örnek şema


Düzenleme: Tablolara birincil anahtar tanımları ekledim. Yukarıda yaptığım noktada tekrarlamak istiyorum: veritabanı, doğruluk / güvenlik önlemi olarak müşteriler tarafından temelde silindi. Bu nedenle, tüm birincil anahtarlar customerkimliği içerir .


2
Hayır, yapmamalısın. Ekstra FK'ye gerek yoktur. Kısıtlama diğer iki FK tarafından uygulanır.
ypercubeᵀᴹ

@ypercube Yedekli bir FK'ye sahip olmanın herhangi bir performans cezası var mı? Aklınıza gelebilecek herhangi bir avantaj var mı? ...
Vektörel

1
@vektor, performans özellikleri muhtemelen bir rdbms'den diğerine değişir, ancak genellikle eklediğiniz her yeni FK için bir performans etkisi elde edersiniz, çünkü PK / FK tablolarından birinde bulunan her ekleme / güncelleme / silme, kısıtlama. Büyük PK tablolarında, bu performans cezası oldukça şiddetli olabilir.
Daniel Hutmacher

Yanıtlar:


6

Bence bu orijinal bir fikir.

resim açıklamasını buraya girin

Dikkat edilmesi gereken ilk şey, LineItem tablosundaki PK'nin {CustomerID, CustomerOrderNo, OdrerItemNo}, örneğin iki tanesinin aksine üç özelliğine sahip olmasıdır .

Dikkat edilmesi gereken ikinci şey, idbir öznitelik için genel adın kullanılmasından kaynaklanan karışıklıktır .

CustomerOrderNoİdeal olarak (1,2,3 ..) her müşteri ve için olmalı OrderItemNoher sipariş için (1,2,3 ...).

Bu mümkünse güzeldir, ancak önceki maksimum değeri arayan bir sorgu gerektirir, örneğin

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

yüksek işlem hacmine sahip ortamlarda genellikle tercih edilmediğinden, bunların esasen aynı amaca hizmet eden bir otomatik artışla değiştirildiğini görmek yaygındır. Bu otomatik incremet'in artık benzersiz olduğu doğrudur, bu nedenle bir ANAHTAR olarak kullanılabilir - ancak bunun için gerekli bir uzlaşma olarak bakmayı seçebilirsiniz OrderItemNo.

Yani, bazı yeniden adlandırma CustomerOrderNo -> OrderNove OrderItemNo-> ItemNoile bu modele gelebilirsiniz

resim açıklamasını buraya girin

Şimdi Orderaşağıdakilere bakarsanız benzersizdir

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

Bir FK olarak hizmet etmek üzere {CustomerID, OrderNo}yayıldığını unutmayın LineItem.

Biraz şaşıyorsanız, bu, örneğinize yakındır, ancak PKs {ItemNo} and {OrderNo}yalnızca - örneğinizdeki iki sütun PK'nin aksine.

Şimdi soru şu, neden böyle bir şeye sadeleştirmiyoruz?

resim açıklamasını buraya girin

Hangi iyi, ama tanıtır YOLU BAĞIMLILIK - Sen katılamaz LineItemile Customerdoğrudan kullanmalıdır Orderkatılmak içinde.


Mümkün olduğunda ilk vakayı tercih ederim - favorinizi seçersiniz. Ve tabii ki, doğrudan FK gerek yoktur LineItemiçin Customerbu üç durumda da.


Etrafı araştırdım, ancak "yol bağımlılığının" "2. derece geçişli ilişki" olarak adlandırdığım şey için yaygın olarak benimsenen bir terim olarak kullanıldığını göremiyorum (terminolojim de muhtemelen yanlış olsa da)
Dai

2

"Öğe" doğrudan "müşteri" referans olmamalıdır, çünkü bu öğenin "sipariş" ima. Dolayısıyla, "öğeler" tablosunda "müşteri" sütunlarına ihtiyacınız olmayacak.

Ürünün müşteri ile olan ilişkisi mevcut yabancı anahtar ile sağlanır.

Orders.id bir kimlik sütunuysa, öğeleri kaldırmayı düşünün. Müşteri tamamen.


1
Teşekkürler, ben "müşteri" de "öğeleri" den "siparişleri" ilk FK dahil olduğunu fark etmedi. Cevabımı buna göre detaylandırdım.
Daniel Hutmacher

@DanielHutmacher Soruyu tablolarımın birincil anahtarlarını içerecek şekilde düzenledim. Bu, düzenlemenizde bahsettiğiniz tuhaf FK'leri açıklar.
vektör

Tamam, cevabımı güncelledim. :)
Daniel Hutmacher

customerTüm tablolarda (ve böylece DB siloing) sahip olağandışı bir yaklaşım olduğunu tahmin ediyorum . İtiraf etmeliyim ki bu sadece önceki işimde gördüğüm bir şey. Sana bir anlam ifade ediyor mu? Daha önce böyle bir tasarım gördün mü?
vektör

Ben eklemleri ortadan kaldırmak için kasıtlı olarak veri denormalize etmek istediğiniz bir datawarehouse (yıldız şeması) yaklaşım gibi görünüyor söyleyebilirim. Veya birincil anahtar bileşik olabilir, yani yalnızca müşteri kimliği sütunu benzersiz olmadığında müşteri A'nın birinci, ikinci, üçüncü sipariş, müşteri B'nin birinci, ikinci sipariş vb.
Daniel Hutmacher
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.