Saya sedang berpikir tentang bagaimana untuk mewakili struktur kompleks dalam database SQL Server.
Pertimbangkan aplikasi yang perlu menyimpan detail kumpulan objek, yang memiliki beberapa atribut, tetapi memiliki banyak lainnya yang tidak umum. Misalnya, paket asuransi komersial dapat mencakup pertanggungjawaban, motor, properti, dan perlindungan ganti rugi dalam catatan kebijakan yang sama.
Ini sepele untuk menerapkan ini dalam C #, dll, karena Anda dapat membuat Kebijakan dengan koleksi Bagian, di mana Bagian diwarisi sebagaimana diperlukan untuk berbagai jenis sampul. Namun, database relasional sepertinya tidak memungkinkan ini dengan mudah.
Saya dapat melihat bahwa ada dua pilihan utama:
Buat tabel Kebijakan, lalu tabel Bagian, dengan semua bidang yang diperlukan, untuk semua kemungkinan variasi, yang sebagian besar akan menjadi nol.
Buat tabel Kebijakan dan banyak tabel Bagian, satu untuk setiap jenis sampul.
Kedua alternatif ini tampaknya tidak memuaskan, terutama karena itu perlu untuk menulis pertanyaan di semua Bagian, yang akan melibatkan banyak gabungan, atau banyak cek kosong.
Apa praktik terbaik untuk skenario ini?
Jawaban:
@Bill Karwin menjelaskan tiga model pewarisan dalam bukunya SQL Antipatterns , ketika mengusulkan solusi untuk antipattern SQL Entity-Attribute-Value . Ini adalah gambaran singkat:
Single Table Inheritance (alias Table Per Hierarchy Inheritance):
Menggunakan tabel tunggal seperti pada opsi pertama Anda mungkin desain yang paling sederhana. Seperti yang Anda sebutkan, banyak atribut yang subtipe-spesifik harus diberi
NULL
nilai pada baris di mana atribut ini tidak berlaku. Dengan model ini, Anda akan memiliki satu tabel kebijakan, yang akan terlihat seperti ini:Menjaga desain tetap sederhana adalah nilai tambah, tetapi masalah utama dengan pendekatan ini adalah sebagai berikut:
Ketika menambahkan subtipe baru, Anda harus mengubah tabel untuk mengakomodasi atribut yang menggambarkan objek baru ini. Ini dapat dengan cepat menjadi masalah ketika Anda memiliki banyak subtipe, atau jika Anda berencana untuk menambahkan subtipe secara teratur.
Basis data tidak akan dapat menegakkan atribut mana yang berlaku dan mana yang tidak, karena tidak ada metadata untuk menentukan atribut mana yang termasuk subtipe mana.
Anda juga tidak dapat menerapkan
NOT NULL
atribut subtipe yang wajib. Anda harus menangani ini di aplikasi Anda, yang secara umum tidak ideal.Warisan Meja Beton:
Pendekatan lain untuk mengatasi pewarisan adalah membuat tabel baru untuk setiap subtipe, mengulangi semua atribut umum di setiap tabel. Sebagai contoh:
Desain ini pada dasarnya akan memecahkan masalah yang diidentifikasi untuk metode tabel tunggal:
Atribut wajib sekarang dapat ditegakkan dengan
NOT NULL
.Menambahkan subtipe baru membutuhkan menambahkan tabel baru alih-alih menambahkan kolom ke yang sudah ada.
Juga tidak ada risiko bahwa atribut yang tidak pantas ditetapkan untuk subtipe tertentu, seperti
vehicle_reg_no
bidang untuk kebijakan properti.Tidak perlu
type
atribut seperti dalam metode tabel tunggal. Jenisnya sekarang ditentukan oleh metadata: nama tabel.Namun model ini juga dilengkapi dengan beberapa kelemahan:
Atribut umum dicampur dengan atribut subtipe spesifik, dan tidak ada cara mudah untuk mengidentifikasi mereka. Basis data juga tidak akan tahu.
Saat mendefinisikan tabel, Anda harus mengulang atribut umum untuk setiap tabel subtipe. Itu jelas bukan KERING .
Mencari semua kebijakan terlepas dari subtipe menjadi sulit, dan akan membutuhkan banyak
UNION
.Ini adalah bagaimana Anda harus menanyakan semua kebijakan terlepas dari jenisnya:
Perhatikan bagaimana menambahkan subtipe baru akan membutuhkan kueri di atas untuk dimodifikasi dengan tambahan
UNION ALL
untuk setiap subtipe. Ini dengan mudah dapat menyebabkan bug di aplikasi Anda jika operasi ini dilupakan.Class Table Inheritance (alias Table Per Type Inheritance):
Ini adalah solusi yang @David sebutkan di jawaban lain . Anda membuat tabel tunggal untuk kelas dasar Anda, yang mencakup semua atribut umum. Kemudian Anda akan membuat tabel spesifik untuk setiap subtipe, yang kunci utamanya juga berfungsi sebagai kunci asing ke tabel dasar. Contoh:
Solusi ini memecahkan masalah yang diidentifikasi dalam dua desain lainnya:
Atribut wajib dapat ditegakkan dengan
NOT NULL
.Menambahkan subtipe baru membutuhkan menambahkan tabel baru alih-alih menambahkan kolom ke yang sudah ada.
Tidak ada risiko bahwa atribut yang tidak pantas ditetapkan untuk subtipe tertentu.
Tidak perlu
type
atribut.Sekarang atribut umum tidak dicampur dengan atribut spesifik subtipe lagi.
Kita bisa tetap KERING, akhirnya. Tidak perlu mengulangi atribut umum untuk setiap tabel subtipe saat membuat tabel.
Mengelola peningkatan otomatis
id
untuk kebijakan menjadi lebih mudah, karena ini dapat ditangani oleh tabel dasar, daripada setiap tabel subtipe yang menghasilkannya secara independen.Mencari semua kebijakan terlepas dari subtipe sekarang menjadi sangat mudah: Tidak
UNION
perlu - hanya aSELECT * FROM policies
.Saya menganggap pendekatan tabel kelas sebagai yang paling cocok dalam kebanyakan situasi.
Nama ketiga model ini berasal dari buku Martin Fowler, Patterns of Enterprise Application Architecture .
sumber
Opsi ke-3 adalah membuat tabel "Kebijakan", lalu tabel "SectionsMain" yang menyimpan semua bidang yang sama di semua jenis bagian. Kemudian buat tabel lain untuk setiap jenis bagian yang hanya berisi bidang yang tidak sama.
Memutuskan yang terbaik tergantung pada berapa banyak bidang yang Anda miliki dan bagaimana Anda ingin menulis SQL Anda. Mereka semua akan bekerja. Jika Anda hanya memiliki beberapa bidang maka saya mungkin akan pergi dengan # 1. Dengan "banyak" bidang saya akan condong ke # 2 atau # 3.
sumber
Dengan informasi yang diberikan, saya akan memodelkan database untuk memiliki yang berikut:
KEBIJAKAN
KEWAJIBAN
SIFAT
... dan seterusnya, karena saya berharap akan ada atribut berbeda yang terkait dengan setiap bagian dari kebijakan. Kalau tidak, mungkin ada satu
SECTIONS
meja dan selain itupolicy_id
, akan adasection_type_code
...Bagaimanapun, ini akan memungkinkan Anda untuk mendukung bagian opsional per kebijakan ...
Saya tidak mengerti apa yang Anda anggap tidak memuaskan tentang pendekatan ini - ini adalah cara Anda menyimpan data sambil mempertahankan integritas referensial dan tidak menggandakan data. Istilah ini "dinormalisasi" ...
Karena SQL berbasis SET, ini agak asing dengan konsep pemrograman prosedural / OO & membutuhkan kode untuk transisi dari satu ranah ke ranah lain. ORM sering dipertimbangkan, tetapi mereka tidak bekerja dengan baik dalam sistem volume tinggi dan kompleks.
sumber
Selain itu pada solusi Daniel Vassallo, jika Anda menggunakan SQL Server 2016+, ada solusi lain yang saya gunakan dalam beberapa kasus tanpa kehilangan kinerja.
Anda bisa membuat tabel hanya dengan bidang umum dan menambahkan satu kolom dengan string JSON yang berisi semua bidang khusus subtipe.
Saya telah menguji desain ini untuk mengelola warisan dan saya sangat senang atas fleksibilitas yang dapat saya gunakan dalam aplikasi relatif.
sumber
Cara lain untuk melakukannya, adalah menggunakan
INHERITS
komponen. Sebagai contoh:Dengan demikian dimungkinkan untuk mendefinisikan warisan antar tabel.
sumber
INHERITS
selain PostgreSQL ? MySQL misalnya?Saya condong ke metode # 1 (tabel Bagian terpadu), demi mengambil seluruh kebijakan secara efisien dengan semua bagian mereka (yang saya anggap sistem Anda akan melakukan banyak hal).
Lebih lanjut, saya tidak tahu versi SQL Server yang Anda gunakan, tetapi pada 2008+ Kolom Jarang membantu mengoptimalkan kinerja dalam situasi di mana banyak nilai dalam kolom adalah NULL.
Pada akhirnya, Anda harus memutuskan seberapa "mirip" bagian kebijakan tersebut. Kecuali mereka berbeda secara substansial, saya pikir solusi yang lebih normal mungkin lebih banyak masalah daripada nilainya ... tetapi hanya Anda yang bisa melakukan panggilan itu. :)
sumber
Sebagai alternatif, pertimbangkan untuk menggunakan basis data dokumen (seperti MongoDB) yang secara asli mendukung struktur data yang kaya dan bersarang.
sumber
Lihatlah jawaban yang saya berikan di sini
Fasih NHibernate pemetaan satu-ke-satu dengan kunci sintetis
sumber