@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:
+------+---------------------+----------+----------------+------------------+
| id | date_issued | type | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
| 1 | 2010-08-20 12:00:00 | MOTOR | 01-A-04004 | NULL |
| 2 | 2010-08-20 13:00:00 | MOTOR | 02-B-01010 | NULL |
| 3 | 2010-08-20 14:00:00 | PROPERTY | NULL | Oxford Street |
| 4 | 2010-08-20 15:00:00 | MOTOR | 03-C-02020 | NULL |
+------+---------------------+----------+----------------+------------------+
\------ COMMON FIELDS -------/ \----- SUBTYPE SPECIFIC FIELDS -----/
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:
--// Table: policies_motor
+------+---------------------+----------------+
| id | date_issued | vehicle_reg_no |
+------+---------------------+----------------+
| 1 | 2010-08-20 12:00:00 | 01-A-04004 |
| 2 | 2010-08-20 13:00:00 | 02-B-01010 |
| 3 | 2010-08-20 15:00:00 | 03-C-02020 |
+------+---------------------+----------------+
--// Table: policies_property
+------+---------------------+------------------+
| id | date_issued | property_address |
+------+---------------------+------------------+
| 1 | 2010-08-20 14:00:00 | Oxford Street |
+------+---------------------+------------------+
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:
SELECT date_issued, other_common_fields, 'MOTOR' AS type
FROM policies_motor
UNION ALL
SELECT date_issued, other_common_fields, 'PROPERTY' AS type
FROM policies_property;
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:
CREATE TABLE policies (
policy_id int,
date_issued datetime,
-- // other common attributes ...
);
CREATE TABLE policy_motor (
policy_id int,
vehicle_reg_no varchar(20),
-- // other attributes specific to motor insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
CREATE TABLE policy_property (
policy_id int,
property_address varchar(20),
-- // other attributes specific to property insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
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 a SELECT * 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 .