@Bill Karwin , SQL Entity-Attribute-Value antipatternine çözümler sunarken SQL Antipatterns kitabında üç miras modeli açıklar . Bu kısa bir genel bakış:
Tek Tablo Mirası (Hiyerarşi Başına Miras Olarak Tablo):
İlk seçeneğinizde olduğu gibi tek bir tablo kullanmak muhtemelen en basit tasarımdır. Bahsettiğiniz gibi, alt türe özgü birçok özelliğe, NULL
bu özelliklerin geçerli olmadığı satırlarda bir değer verilmelidir . Bu modelle, aşağıdaki gibi görünen bir politika tablonuz olur:
+------+---------------------+----------+----------------+------------------+
| 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 -----/
Tasarımı basit tutmak bir artıdır, ancak bu yaklaşımla ilgili ana problemler şunlardır:
Yeni alt türler ekleme söz konusu olduğunda, bu yeni nesneleri tanımlayan niteliklere uyum sağlamak için tabloyu değiştirmeniz gerekir. Bu, birçok alt türünüz olduğunda veya düzenli olarak alt türler eklemeyi planladığınızda hızlı bir şekilde sorunlu hale gelebilir.
Hangi özniteliklerin hangi alt türlere ait olduğunu tanımlayacak hiçbir meta veri olmadığından, veritabanı hangi özniteliklerin uygulanıp hangilerinin uygulanmadığını uygulayamaz.
Ayrıca, NOT NULL
zorunlu olması gereken bir alt türün niteliklerini uygulayamazsınız . Genel olarak ideal olmayan başvurunuzda bunu ele almanız gerekir.
Beton Masa Mirası:
Kalıtımla başa çıkmanın bir başka yaklaşımı, her bir alt tür için yeni bir tablo oluşturmak ve her tablodaki tüm ortak özellikleri tekrarlamaktır. Örneğin:
--// 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 |
+------+---------------------+------------------+
Bu tasarım temel olarak tek tablo yöntemi için belirlenen sorunları çözecektir:
Zorunlu özellikler artık uygulanabilir NOT NULL
.
Yeni bir alt tür eklemek için varolan bir alt kısma sütun eklemek yerine yeni bir tablo eklemek gerekir.
Ayrıca, vehicle_reg_no
bir mülkiyet ilkesine ilişkin alan gibi belirli bir alt tür için uygun olmayan bir özniteliğin ayarlanması riski yoktur .
type
Tek tablo yönteminde olduğu gibi özniteliğe gerek yoktur . Tür artık meta veriler tarafından tanımlanmıştır: tablo adı.
Bununla birlikte, bu model birkaç dezavantajla birlikte gelir:
Ortak öznitelikler alt türe özgü özniteliklerle karıştırılır ve bunları tanımlamanın kolay bir yolu yoktur. Veritabanı da bilmiyor.
Tabloları tanımlarken, her bir alt tür tablosu için ortak özellikleri tekrarlamanız gerekir. Kesinlikle KURU değil .
Alt türden bağımsız olarak tüm politikaları aramak zorlaşır ve bir grup UNION
s gerektirir .
Türüne bakılmaksızın tüm politikaları şu şekilde sorgulamanız gerekir:
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;
Yeni alt türler eklemenin, yukarıdaki sorgunun UNION ALL
her alt tür için bir ek ile nasıl değiştirilmesini gerektirdiğini unutmayın . Bu işlem unutulursa, uygulamanızda hatalara neden olabilir.
Sınıf Tablosu Devralma (diğer adıyla Tür Devralma Tablosu):
@David'in diğer cevapta bahsettiği çözüm budur . Temel sınıfınız için tüm ortak öznitelikleri içeren tek bir tablo oluşturursunuz. Ardından, her bir alt tür için, birincil anahtarı da temel tabloya yabancı anahtar işlevi gören belirli tablolar oluşturacaksınız . Misal:
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)
);
Bu çözüm diğer iki tasarımda tanımlanan sorunları çözer:
Zorunlu özellikler uygulanabilir NOT NULL
.
Yeni bir alt tür eklemek için varolan bir alt kısma sütun eklemek yerine yeni bir tablo eklemek gerekir.
Belirli bir alt tür için uygun olmayan bir öznitelik ayarlanma riski yoktur.
Özelliğe gerek yok type
.
Artık ortak özellikler artık alt tip spesifik özelliklerle karıştırılmamaktadır.
Nihayet KURU kalabiliriz. Tabloları oluştururken her alt tip tablo için ortak nitelikleri tekrarlamaya gerek yoktur.
İlkeler için otomatik olarak artırmayı yönetmek id
daha kolay hale gelir, çünkü bu, bağımsız olarak oluşturulan her alt tür tablo yerine temel tablo tarafından işlenebilir.
Alt türden bağımsız olarak tüm politikaları aramak artık çok kolay: Gerek yok UNION
- sadece a SELECT * FROM policies
.
Sınıf tablosu yaklaşımını çoğu durumda en uygun olarak görüyorum.
Bu üç modelin adları Martin Fowler'in Kurumsal Uygulama Mimarisi Desenleri kitabından alınmıştır .