Sejauh Pertanyaan ini merupakan kelanjutan dari apakah penerapan pola desain jenis / subtipe saya (untuk subkelas yang saling eksklusif) benar? , yang merupakan kelanjutan dari Tidak tahu bagaimana mengubah entitas variabel menjadi tabel relasional , saya akan bertanya: apa sebenarnya yang Anda coba optimalkan? Penyimpanan? Model objek? Kompleksitas kueri? Performa permintaan? Ada trade-off ketika mengoptimalkan satu aspek vs yang lain karena Anda tidak dapat mengoptimalkan semua aspek secara bersamaan.
Saya sepenuhnya setuju dengan poin Remus mengenai:
- Ada pro dan kontra untuk setiap pendekatan (yaitu faktor "itu tergantung" yang selalu ada), dan
- Prioritas pertama adalah efisiensi model data (model data yang tidak efisien tidak dapat diperbaiki dengan kode aplikasi yang bersih dan / atau efisien)
Yang mengatakan, pilihan yang Anda hadapi adalah antara yang berikut, diatur dalam urutan paling tidak normalisasi ke paling normal:
- mempromosikan properti
E
ke Tabel tipe dasar
- menjaganya dalam beberapa sub-tipe Tabel
- sepenuhnya normal
E
keluar ke tabel sub-kelas perantara baru pada tingkat yang sama dengan C
, itu A
dan B
akan langsung menjadi sub-kelas dari ( @ jawaban MDCCL )
Mari kita lihat setiap opsi:
Pindahkan properti E
ke Tabel tipe dasar
PRO
- Kompleksitas permintaan berkurang untuk query yang membutuhkan
E
tetapi tidak X
, Y
atau Z
.
- Berpotensi lebih efisien untuk query yang membutuhkan
E
tetapi tidak X
, Y
atau Z
(query terutama agregat) karena tidak ada BERGABUNG.
- Berpotensi membuat indeks aktif
(D, E)
(dan jika demikian, berpotensi Indeks yang Difilter di (D, E)
mana EntityType <> C
, jika kondisi seperti itu dibolehkan)
Kon
- Tidak dapat menandai
E
sebagaiNOT NULL
- Perlu tambahan
CHECK CONSTRAINT
pada tabel tipe-dasar untuk memastikan bahwa E IS NULL
ketika EntityType = C
(meskipun ini bukan masalah besar)
- Perlu mengedukasi pengguna model data mengapa
E
harus NULL
, dan bahkan harus diabaikan sepenuhnya, ketika EntityType = C
.
- Sedikit kurang efisien ketika
E
merupakan tipe dengan panjang tetap, dan sebagian besar baris adalah untuk EntityType C
(yaitu tidak menggunakan E
karenanya NULL
), dan tidak menggunakan salah satu SPARSE
opsi pada kolom atau Kompresi Data pada Indeks Clustered
- Berpotensi kurang efisien untuk kueri yang tidak perlu
E
karena kehadiran E
dalam tabel tipe dasar akan meningkatkan ukuran setiap baris yang pada gilirannya mengurangi jumlah baris yang dapat ditampung pada halaman data. Tapi ini sangat tergantung pada tipe data yang tepat E
, FILLFACTOR, berapa banyak baris dalam tabel tipe-dasar, dll.
Simpan properti E
di setiap sub-jenis Tabel
PRO
- Model data yang lebih bersih (yaitu tidak perlu khawatir tentang mendidik orang lain mengapa kolom
E
dalam tabel tipe dasar tidak boleh digunakan karena "itu benar-benar tidak ada")
- Mungkin lebih mirip dengan objek-model
- Dapat menandai kolom seolah-
NOT NULL
olah ini adalah properti yang diperlukan entitas
- Tidak perlu tambahan
CHECK CONSTRAINT
pada tabel tipe-dasar untuk memastikan bahwa E IS NULL
ketika EntityType = C
(meskipun ini bukan keuntungan besar)
Kon
- Perlu BERGABUNG ke sub-tipe Tabel untuk mendapatkan properti ini
- Berpotensi sedikit kurang efisien saat membutuhkan
E
, karena BERGABUNG, tergantung pada berapa banyak baris A
+ yang B
Anda miliki dibandingkan dengan berapa banyak baris yang C
ada.
- Sedikit lebih sulit / rumit untuk operasi yang hanya berurusan dengan entitas
A
dan B
(dan tidak C
) sebagai "tipe" yang sama. Tentu saja, Anda bisa mengabstraksi ini melalui tampilan yang melakukan a UNION ALL
antara SELECT
tabel JOINed untuk A
dan tabel JOINed lain SELECT
untuk B
. Itu akan mengurangi kompleksitas kueri SELECT tetapi tidak begitu membantu untuk INSERT
dan UPDATE
kueri.
- Bergantung pada permintaan spesifik dan seberapa sering dieksekusi, ini bisa menjadi inefisiensi potensial dalam kasus di mana memiliki indeks
(D, E)
akan sangat membantu satu atau lebih sering digunakan query, karena mereka tidak dapat diindeks bersama.
Normalisasi E
ke Tabel perantara antara kelas dasar dan A
&B
(Harap dicatat bahwa saya suka jawaban @ MDCCL sebagai alternatif yang layak, tergantung pada keadaan. Berikut ini tidak dimaksudkan sebagai kritik ketat terhadap pendekatan itu, tetapi sebagai cara menambahkan beberapa perspektif - milik saya, tentu saja - dengan mengevaluasi itu dalam konteks yang sama dengan dua opsi yang telah saya usulkan. Ini akan membuatnya lebih mudah untuk memperjelas apa yang saya lihat sebagai perbedaan relatif antara normalisasi penuh dan pendekatan normalisasi parsial saat ini.)
PRO
- model data sepenuhnya dinormalisasi (tidak mungkin ada yang salah dengan ini, mengingat itu adalah apa yang RDBMS dirancang untuk dilakukan)
- mengurangi kompleksitas kueri untuk kueri yang membutuhkan
A
dan B
, tetapi tidak C
(yaitu tidak perlu dua kueri yang digabungkan melalui UNION ALL
)
Kon
- sedikit lebih banyak ruang yang digunakan (
Bar
tabel menduplikasi ID, dan ada kolom baru, BarTypeCode
) [dapat diabaikan, tetapi sesuatu yang harus diperhatikan]
- sedikit peningkatan dalam kompleksitas kueri karena tambahan
JOIN
diperlukan untuk mendapatkan salah satu A
atauB
- peningkatan luas permukaan untuk penguncian, sebagian besar pada
INSERT
( DELETE
dapat ditangani secara implisit melalui penandaan Kunci Asing sebagai ON CASCADE DELETE
) karena Transaksi akan diadakan terbuka sedikit lebih lama pada tabel kelas dasar (yaitu Foo
) [dapat diabaikan, tetapi sesuatu yang harus diperhatikan]
tidak ada pengetahuan langsung dari jenis yang sebenarnya - A
atau B
- dalam Tabel basis kelas, Foo
; hanya tahu dari jenis Br
yang dapat berupa A
atau B
:
Artinya, jika Anda perlu melakukan kueri atas informasi basis umum tetapi perlu mengategorikan berdasarkan tipe entitas atau memfilter satu atau lebih tipe entitas, maka tabel kelas dasar tidak memiliki informasi yang cukup, dalam hal ini Anda perlu LEFT JOIN
yang Bar
meja. Ini juga akan mengurangi efektivitas pengindeksan FooTypeCode
kolom.
tidak ada pendekatan yang konsisten untuk berinteraksi dengan A
& B
vs C
:
Berarti, jika setiap entitas berhubungan langsung dengan tabel kelas-dasar sedemikian sehingga hanya ada satu yang BERGABUNG untuk mendapatkan entitas penuh, maka setiap orang dapat lebih cepat dan mudah membangun keakraban dalam hal bekerja dengan model data. Akan ada pendekatan umum untuk kueri / Prosedur Tersimpan yang membuatnya lebih cepat berkembang dan kecil kemungkinannya memiliki bug. Pendekatan yang konsisten juga membuatnya lebih cepat dan lebih mudah untuk menambahkan sub-tipe baru di masa depan.
berpotensi kurang dapat beradaptasi dengan aturan bisnis yang berubah seiring waktu:
Artinya, segala sesuatu selalu berubah, dan cukup mudah untuk E
naik ke Tabel kelas dasar jika menjadi umum untuk semua sub-tipe. Juga cukup mudah untuk memindahkan properti umum ke sub-tipe jika perubahan sifat entitas membuat perubahan bernilai sementara. Cukup mudah untuk membagi sub-tipe menjadi dua sub-tipe (cukup buat SubTypeID
nilai lain ) atau menggabungkan dua atau lebih sub-tipe menjadi satu. Sebaliknya, bagaimana jika E
nanti menjadi milik bersama semua sub-tipe? Maka lapisan perantara dari Bar
tabel akan menjadi tidak berarti, dan kompleksitas yang ditambahkan tidak akan sia-sia. Tentu saja, tidak mungkin untuk mengetahui apakah perubahan seperti itu akan terjadi dalam 5 atau bahkan 10 tahun, jadi Bar
tabelnya belum tentu, atau bahkan sangat mungkin, ide buruk (itulah sebabnya saya katakan " berpotensi kurang beradaptasi"). Ini hanya beberapa hal yang perlu dipertimbangkan; itu pertaruhan di kedua arah.
pengelompokan yang berpotensi tidak pantas:
Berarti, hanya karena E
properti dibagi antara jenis entitas A
dan B
tidak berarti itu A
dan B
harus dikelompokkan bersama. Hanya karena hal-hal "terlihat" sama (yaitu sifat yang sama) tidak berarti bahwa mereka sama.
Ringkasan
Seperti halnya memutuskan apakah / kapan melakukan denasionalisasi, cara terbaik mendekati situasi khusus ini tergantung pada pertimbangan aspek-aspek penggunaan model data berikut ini dan memastikan bahwa manfaatnya lebih besar daripada biayanya:
- berapa banyak baris yang akan Anda miliki untuk setiap EntityType (lihat setidaknya 5 tahun ke depan, dengan asumsi pertumbuhan di atas rata-rata)
- berapa GB masing-masing tabel ini (tipe dasar dan sub-tipe) dalam 5 tahun?
- apa tipe data spesifik properti
E
- apakah hanya satu properti atau ada beberapa, atau bahkan beberapa, properti
- pertanyaan apa yang Anda perlukan yang membutuhkan
E
dan seberapa sering mereka akan dieksekusi
- pertanyaan apa yang Anda perlukan yang tidak perlu
E
dan seberapa sering mereka akan dieksekusi
Saya pikir saya cenderung default untuk menjaga E
dalam tabel sub-tipe yang terpisah karena, paling tidak, "bersih". Saya akan mempertimbangkan pindah E
ke tabel tipe dasar JIKA: sebagian besar baris bukan untuk EntityType C
; dan jumlah baris setidaknya dalam jutaan; dan saya lebih sering mengeksekusi kueri yang membutuhkan E
dan / atau kueri yang akan mendapat manfaat dari indeks pada (D, E)
pelaksanaan yang sangat sering dan / atau memerlukan sumber daya sistem yang cukup sehingga memiliki indeks mengurangi pemanfaatan sumber daya secara keseluruhan, atau setidaknya mencegah lonjakan konsumsi sumber daya yang melampaui tingkat yang dapat diterima atau bertahan cukup lama untuk menyebabkan pemblokiran yang berlebihan dan / atau peningkatan deadlock.
MEMPERBARUI
OP mengomentari jawaban ini bahwa:
Majikan saya mengubah logika bisnis, menghapus E sama sekali!
Perubahan ini sangat penting karena persis apa yang saya prediksikan mungkin terjadi di sub "CONs" dari bagian "Normalisasi E
ke tabel perantara antara kelas-dasar dan A
& B
" di atas (poin ke-6). Masalah khusus adalah betapa mudah / sulitnya untuk memperbaiki model data ketika perubahan tersebut terjadi (dan selalu terjadi). Beberapa akan berpendapat bahwa model data apa pun dapat di-refactored / diubah, jadi mulailah dengan yang ideal. Tetapi sementara itu benar pada tingkat teknis bahwa apa pun dapat di refactored, realitas situasi adalah masalah skala.
Sumber daya tidak terbatas, tidak hanya CPU / Disk / RAM, tetapi juga sumber daya pengembangan: waktu dan uang. Bisnis secara konstan menetapkan prioritas pada proyek karena sumber daya tersebut sangat terbatas. Dan cukup sering (setidaknya dalam pengalaman saya), proyek untuk mendapatkan efisiensi (bahkan kinerja sistem maupun pengembangan lebih cepat / lebih sedikit bug) diprioritaskan di bawah proyek yang meningkatkan fungsionalitas. Walaupun hal ini membuat frustasi bagi kami orang-orang teknis karena kami memahami apa manfaat jangka panjang dari proyek-proyek refactoring, itu hanya sifat bisnis bahwa orang-orang bisnis yang kurang teknis, lebih mudah melihat hubungan langsung antara fungsi baru dan baru. pendapatan. Intinya adalah: "kami akan kembali untuk memperbaikinya nanti" == "
Dengan mengingat hal itu, jika ukuran data cukup kecil sehingga perubahan dapat dibuat sangat kueri, dan / atau Anda memiliki jendela pemeliharaan yang cukup panjang untuk tidak hanya melakukan perubahan tetapi juga memutar kembali jika terjadi sesuatu salah, lalu menormalkan E
ke Tabel perantara antara tabel kelas dasar dan tabel A
& B
sub-kelas bisa berfungsi (meskipun itu masih membuat Anda tidak memiliki pengetahuan langsung tentang jenis tertentu ( A
atauB
) di tabel kelas dasar). TETAPI, jika Anda memiliki ratusan juta baris dalam tabel ini, dan sejumlah besar kode merujuk pada tabel (kode yang harus diuji ketika perubahan dilakukan), maka biasanya membayar lebih pragmatis daripada idealis. Dan ini adalah lingkungan yang harus saya tangani selama bertahun-tahun: 987 juta baris & 615 GB di tabel kelas dasar, tersebar di 18 server. Dan begitu banyak kode mengenai tabel ini (tabel kelas dasar dan kelas sub-kelas) sehingga ada banyak hambatan - kebanyakan dari manajemen tetapi kadang-kadang dari anggota tim lainnya - untuk membuat perubahan apa pun karena jumlah pengembangan dan Sumber daya QA yang perlu dialokasikan.
Jadi, sekali lagi, pendekatan "terbaik" hanya dapat ditentukan situasi demi situasi: Anda perlu mengetahui sistem Anda (yaitu seberapa banyak data dan bagaimana semua tabel dan kode berhubungan), bagaimana menyelesaikan refactoring, dan orang-orang Anda bekerja dengan (tim Anda dan mungkin manajemen - dapatkah Anda menerima dukungan mereka untuk proyek semacam itu?). Ada beberapa perubahan yang telah saya sebutkan dan rencanakan untuk 1 - 2 tahun, dan mengambil beberapa sprint / rilis untuk mendapatkan mungkin 85% dari mereka diimplementasikan. Tetapi jika Anda hanya memiliki <1 juta baris dan tidak banyak kode yang terikat pada tabel ini, maka Anda mungkin dapat memulai dari sisi yang lebih ideal / "murni".
Ingat saja, ke mana pun Anda memilih untuk pergi, perhatikan bagaimana model itu bekerja setidaknya selama 2 tahun ke depan (jika mungkin). Perhatikan apa yang berhasil dan apa yang menyebabkan rasa sakit, bahkan jika itu tampak seperti ide terbesar pada saat itu (yang berarti Anda juga perlu membiarkan diri Anda menerima mengacau - kita semua melakukannya - sehingga Anda dapat dengan jujur mengevaluasi poin rasa sakit ). Dan perhatikan mengapa keputusan tertentu berhasil atau tidak sehingga Anda dapat membuat keputusan yang lebih cenderung menjadi "lebih baik" lain kali :-).
Menurut interpretasi saya tentang spesifikasi Anda, Anda ingin menemukan metode untuk mengimplementasikan dua struktur subtipe-subtipe supertipe yang berbeda (namun terhubung ) .
Untuk mengekspos pendekatan untuk mencapai tugas yang disebutkan, saya akan menambah skenario yang dipermasalahkan dua tipe entitas hipotetis klasik yang disebut
Foo
danBar
, yang akan saya jelaskan di bawah.Peraturan bisnis
Berikut adalah beberapa pernyataan yang akan membantu saya membuat model yang logis:
A Foo is either one Bar or one C
A Foo is categorized by one FooType
A Bar is either one A or one C
A Bar is classified by one BarType
Model yang logis
Dan kemudian, model logis IDEF1X [1] yang dihasilkan ditunjukkan pada Gambar 1 (dan Anda juga dapat mengunduhnya dari Dropbox sebagai PDF ):
Tambahan Foo and Bar
Saya tidak menambah
Foo
danBar
membuat model terlihat lebih baik, tetapi untuk membuatnya lebih ekspresif. Saya menganggap mereka penting karena hal berikut:Saat
A
danB
membagikan atribut yang dinamaiE
, fitur ini menunjukkan bahwa mereka adalah tipe subentitas dari konsep , peristiwa , orang , pengukuran , dll. Yang berbeda, yang saya wakili dengan menggunakanBar
tipe superentity yang, pada gilirannya, adalah tipe subentityFoo
, yang menyimpanD
atribut di bagian atas hierarki.Sejak
C
hanya saham satu atribut dengan sisa jenis entitas di bawah diskusi, yaitu,D
, aspek ini menyindir bahwa itu adalah jenis subentity dari jenis lain dari konsep , acara , orang , pengukuran , dll, jadi saya digambarkan keadaan ini berdasarkan yangFoo
super entitas jenis.Namun, ini hanya asumsi, dan karena database relasional dimaksudkan untuk mencerminkan semantik konteks bisnis tertentu secara akurat, Anda harus mengidentifikasi dan mengklasifikasikan semua hal yang menarik di domain spesifik Anda sehingga Anda dapat, tepatnya, menangkap lebih banyak makna .
Faktor penting pada fase desain
Sangat berguna untuk menyadari fakta bahwa, dengan mengesampingkan semua terminologi, klaster supertipe-subtipe eksklusif adalah hubungan biasa. Mari kita gambarkan situasi dengan cara berikut:
Dengan demikian, ada korespondensi (atau kardinalitas) dari satu-ke-satu (1: 1) dalam kasus ini.
Seperti yang Anda ketahui dari posting sebelumnya, atribut diskriminator (kolom, ketika diimplementasikan) memainkan peran penting ketika membuat asosiasi dari sifat ini, karena itu menunjukkan contoh subtipe yang benar dengan mana supertipe terhubung . The migrasi dari PRIMARY KEY dari (i) supertype untuk (ii) subtipe juga penting utama.
Struktur DDL beton
Dan kemudian saya menulis struktur DDL yang didasarkan pada model logis yang disajikan di atas:
Dengan struktur ini, Anda menghindari penyimpanan tanda NULL di tabel dasar (atau relasi ) Anda, yang akan menimbulkan ambiguitas pada basis data Anda.
Integritas, konsistensi, dan pertimbangan lain
Setelah Anda menerapkan basis data Anda, Anda harus memastikan bahwa (a) setiap baris supertype eksklusif selalu dilengkapi oleh mitra subtipe yang sesuai dan, pada gilirannya, menjamin bahwa (b) baris subtipe tersebut kompatibel dengan nilai yang terkandung dalam kolom diskriminator supertype. . Oleh karena itu, cukup mudah untuk menggunakan ACID
TRANSACTIONS
untuk memastikan bahwa kondisi ini terpenuhi dalam database Anda.Anda tidak boleh menyerah pada kesehatan logis, ekspresi diri, dan akurasi database Anda, ini adalah aspek yang jelas membuat database Anda lebih solid.
Dua jawaban yang diposting sebelumnya sudah termasuk poin terkait yang tentu saja layak dipertimbangkan ketika merancang, membuat dan mengelola basis data Anda dan program aplikasinya.
Mengambil data dengan cara LIHAT definisi
Anda dapat mengatur beberapa tampilan yang menggabungkan kolom dari kelompok subtipe-supertipe yang berbeda , sehingga Anda dapat mengambil data secara langsung tanpa, misalnya, menulis klausa JOIN yang diperlukan setiap waktu. Dengan cara ini, Anda dapat PILIH langsung DARI VIEW ( relasi turunan atau tabel ) yang menarik dengan mudah.
Seperti yang Anda lihat, "Ted" Codd, tidak diragukan lagi, seorang jenius. Alat yang diwariskannya cukup kuat dan elegan, dan, tentu saja, terintegrasi dengan baik satu sama lain.
Sumber terkait
Jika Anda ingin menganalisis beberapa basis data yang luas yang melibatkan hubungan supertype-subtype, Anda akan menemukan nilai dari jawaban luar biasa yang diajukan oleh @PerformanceDBA untuk pertanyaan Stack Overflow berikut:
Database historis / dapat diaudit .
[O] ne table atau banyak untuk banyak acara yang berbeda tetapi berinteraksi? , yang terdiri dari subtipe bersarang .
Catatan
1. Definisi Integrasi untuk Pemodelan Informasi ( IDEF1X ) adalah teknik pemodelan data yang sangat direkomendasikan yang ditetapkan sebagai standar pada bulan Desember 1993 oleh Institut Standar dan Teknologi Nasional ( NIST ) Amerika Serikat . Ini didasarkan pada (a) bahan teoretis awal yang ditulis oleh Dr. EF Codd; pada (b) yang Entity-Relationship tampilan data, yang dikembangkan oleh Dr. PP Chen ; dan juga pada (c) Teknik Desain Basis Data Logis, yang dibuat oleh Robert G. Brown. Perlu dicatat bahwa IDEF1X diformalkan dengan cara logika tingkat pertama.
sumber
E
semuanya! Alasan untuk menerima jawaban pengguna srutzky adalah karena memberikan poin yang baik yang membantu saya untuk membuat keputusan saya memilih rute yang paling efisien. Kalau bukan karena itu saya akan menerima jawaban Anda. Saya telah membatalkan jawaban Anda sebelumnya. Terima kasih lagi!