Haruskah saya menambahkan kunci asing transitif?

11

Contoh sederhana: ada meja pelanggan.

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

Semua data lain dalam database harus terhubung ke Customer, jadi misal Ordersterlihat seperti ini:

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

Misalkan sekarang ada tabel yang menghubungkan ke 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)
)

Haruskah saya menambahkan kunci asing terpisah dari Itemske Customers?

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

Sebagai gantinya gambar: haruskah saya menambahkan garis putus-putus / FK?

Contoh skema sederhana


Sunting: Saya telah menambahkan definisi kunci utama ke tabel. Saya ingin mengulang kembali pada poin yang saya buat di atas: basis data pada dasarnya dibungkam oleh pelanggan, sebagai ukuran kebenaran / keamanan. Oleh karena itu, semua kunci utama berisi customerID.

vektor
sumber
2
Tidak, seharusnya tidak. Tidak perlu untuk FK tambahan. Kendala itu ditegakkan oleh dua FK lainnya.
ypercubeᵀᴹ
@ypercube Apakah ada penalti kinerja karena memiliki FK yang berlebihan? Adakah keuntungan yang dapat Anda pikirkan? ...
vektor
1
@vektor, aspek kinerja mungkin berbeda dari satu rdbms ke yang lain, tetapi secara umum, Anda mendapatkan dampak kinerja untuk setiap FK baru yang Anda tambahkan, karena setiap sisipan / perbarui / hapus di salah satu tabel PK / FK harus diperiksa terhadap paksaan. Dengan tabel PK besar, penalti kinerja ini bisa sangat parah.
Daniel Hutmacher

Jawaban:

6

Saya pikir ini adalah ide asli.

masukkan deskripsi gambar di sini

Hal pertama yang perlu diperhatikan adalah bahwa PK pada tabel LineItem memiliki tiga atribut {CustomerID, CustomerOrderNo, OdrerItemNo}, bukan hanya dua dalam contoh Anda.

Hal kedua yang perlu diperhatikan adalah kebingungan yang dihasilkan dari penggunaan idnama generik untuk atribut.

The CustomerOrderNoidealnya harus (1,2,3 ..) untuk setiap pelanggan dan OrderItemNo(1,2,3 ...) untuk setiap pesanan.

Yah, ini bagus jika memungkinkan, tetapi membutuhkan kueri yang mencari nilai maks sebelumnya, seperti

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

yang sering tidak disukai di lingkungan volume transaksi tinggi, jadi itu umum untuk melihat ini digantikan oleh kenaikan otomatis, pada dasarnya melayani tujuan yang sama. Memang benar bahwa incremet otomatis ini sekarang unik, sehingga dapat digunakan sebagai KUNCI - tetapi Anda dapat memilih untuk melihatnya sebagai kompromi yang diperlukan untuk OrderItemNo.

Jadi, dengan beberapa penggantian nama CustomerOrderNo -> OrderNodan OrderItemNo-> ItemNoAnda dapat tiba di model ini

masukkan deskripsi gambar di sini

Jadi sekarang jika Anda melihat Orderyang berikut ini adalah unik

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

Catatan yang {CustomerID, OrderNo}disebarkan ke LineItemuntuk melayani sebagai FK.

Jika Anda sedikit menyipit, ini dekat dengan contoh Anda, tetapi dengan PKs {ItemNo} and {OrderNo}hanya - yang bertentangan dengan dua PK kolom dari contoh Anda.

Sekarang pertanyaannya adalah, mengapa tidak menyederhanakan sesuatu seperti ini?

masukkan deskripsi gambar di sini

Yang baik-baik saja, tetapi memperkenalkan PATH DEPENDENCE - Anda tidak dapat bergabung LineItemdengan Customerlangsung, harus menggunakan Orderdalam bergabung.


Saya lebih suka case pertama jika memungkinkan - Anda memilih favorit Anda. Dan jelas, tidak ada kebutuhan untuk FK langsung dari LineItemke Customertiga kasus ini.

Damir Sudarevic
sumber
Saya mencari-cari, tetapi saya tidak bisa melihat "ketergantungan jalan" digunakan sebagai istilah yang diadopsi secara luas untuk apa yang saya sebut sebagai "hubungan transitif tingkat 2" (meskipun terminologi saya mungkin juga salah)
Dai
2

"Item" tidak boleh merujuk "pelanggan" secara langsung, karena ini tersirat oleh "pesanan" item. Jadi, Anda tidak memerlukan kolom "pelanggan" pada tabel "item" sama sekali.

Hubungan barang dengan pelanggan dipastikan dengan kunci asing yang ada.

Jika orders.id adalah kolom identitas, pertimbangkan untuk menghapus item.customer semuanya.

Daniel Hutmacher
sumber
1
Terima kasih, saya tidak melihat bahwa "pelanggan" juga termasuk dalam FK pertama dari "barang" hingga "pesanan". Saya telah menguraikan jawaban saya sesuai.
Daniel Hutmacher
@DanielHutmacher Saya telah mengedit pertanyaan yang berisi kunci utama tabel saya. Ini menjelaskan FK aneh yang Anda sebutkan di suntingan Anda.
vektor
Oke, saya sudah memperbarui jawaban saya. :)
Daniel Hutmacher
Saya menduga bahwa memiliki customersemua tabel (dan dengan demikian silo DB) adalah pendekatan yang tidak biasa. Saya harus mengakui bahwa itu hanya sesuatu yang saya lihat dalam pekerjaan saya sebelumnya. Apakah itu masuk akal bagi Anda? Pernahkah Anda melihat desain seperti itu sebelumnya?
vektor
Saya akan mengatakan itu terlihat seperti pendekatan datawarehouse (skema bintang), di mana Anda ingin secara sengaja mendenormalkan data untuk menghilangkan gabungan. Atau kunci utama dapat berupa komposit, yaitu urutan pertama, kedua, ketiga pelanggan A, urutan pertama, kedua, dan seterusnya - ketika kolom id pesanan saja tidak unik.
Daniel Hutmacher