@Bill Karwin ने SQL एंटिटी-एट्रीब्यूट-वैल्यू एंटीपैटर्न के समाधान का प्रस्ताव करते हुए, अपनी SQL Antipatterns पुस्तक में तीन विरासत मॉडल का वर्णन किया है । यह एक संक्षिप्त अवलोकन है:
एकल तालिका वंशानुक्रम (उर्फ तालिका प्रति पदानुक्रम वंशानुक्रम):
अपने पहले विकल्प के रूप में एकल तालिका का उपयोग करना संभवतः सबसे सरल डिजाइन है। जैसा कि आपने उल्लेख किया है, उप-विशिष्ट-विशिष्ट कई विशेषताएं उन NULL
पंक्तियों पर एक मान देनी होंगी जहाँ ये विशेषताएँ लागू नहीं होती हैं। इस मॉडल के साथ, आपके पास एक नीति तालिका होगी, जो कुछ इस तरह दिखाई देगी:
+------+---------------------+----------+----------------+------------------+
| 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 -----/
डिजाइन को सरल रखना एक प्लस है, लेकिन इस दृष्टिकोण के साथ मुख्य समस्याएं निम्नलिखित हैं:
जब नई उपप्रकारों को जोड़ने की बात आती है, तो आपको इन नई वस्तुओं का वर्णन करने वाली विशेषताओं को समायोजित करने के लिए तालिका को बदलना होगा। जब आपके पास कई उपप्रकार होते हैं, या यदि आप नियमित आधार पर उपप्रकारों को जोड़ने की योजना बनाते हैं, तो यह जल्दी समस्याग्रस्त हो सकता है।
डेटाबेस लागू नहीं कर पाएगा कि कौन सी विशेषताएँ लागू होती हैं और कौन सी नहीं, क्योंकि कोई मेटाडेटा यह निर्धारित करने के लिए नहीं है कि कौन सी विशेषताएँ किस उप-वर्ग से संबंधित हैं।
आप NOT NULL
एक उप-प्रकार की विशेषताओं पर भी लागू नहीं कर सकते हैं जो अनिवार्य होनी चाहिए। आपको इसे अपने एप्लिकेशन में संभालना होगा, जो सामान्य रूप से आदर्श नहीं है।
कंक्रीट टेबल विरासत:
विरासत से निपटने के लिए एक और दृष्टिकोण प्रत्येक उपप्रकार के लिए एक नई तालिका बनाना है, प्रत्येक तालिका में सभी सामान्य विशेषताओं को दोहराते हुए। उदाहरण के लिए:
--// 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 |
+------+---------------------+------------------+
यह डिज़ाइन मूल रूप से एकल तालिका पद्धति के लिए पहचानी गई समस्याओं को हल करेगी:
अनिवार्य विशेषताओं को अब लागू किया जा सकता है NOT NULL
।
एक नया उपप्रकार जोड़ने के लिए एक मौजूदा एक में कॉलम जोड़ने के बजाय एक नई तालिका जोड़ना आवश्यक है।
इसमें कोई जोखिम नहीं है कि किसी विशेष उप-प्रकार के लिए एक अनुचित विशेषता सेट की गई है, जैसे कि vehicle_reg_no
संपत्ति नीति के लिए फ़ील्ड।
type
एकल तालिका पद्धति में विशेषता के लिए कोई आवश्यकता नहीं है । प्रकार अब मेटाडेटा द्वारा परिभाषित किया गया है: तालिका नाम।
हालांकि यह मॉडल कुछ नुकसान के साथ भी आता है:
सामान्य विशेषताओं को उपप्रकार विशिष्ट विशेषताओं के साथ मिलाया जाता है, और उन्हें पहचानने का कोई आसान तरीका नहीं है। डेटाबेस या तो पता नहीं चलेगा।
तालिकाओं को परिभाषित करते समय, आपको प्रत्येक उपप्रकार तालिका के लिए सामान्य विशेषताओं को दोहराना होगा। यह निश्चित रूप से नहीं है DRY ।
उपप्रकार की परवाह किए बिना सभी नीतियों के लिए खोज करना मुश्किल हो जाता है, और इसके लिए एक समूह की आवश्यकता होगी UNION
।
इस प्रकार से आपको सभी नीतियों को क्वेरी करना होगा:
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;
ध्यान दें कि नए उप-योगों को जोड़ने के UNION ALL
लिए प्रत्येक उप-प्रकार के लिए एक अतिरिक्त के साथ संशोधित करने के लिए उपरोक्त क्वेरी की आवश्यकता होगी । यदि यह ऑपरेशन भूल जाता है तो यह आपके एप्लिकेशन में आसानी से बग पैदा कर सकता है।
क्लास टेबल इनहेरिटेंस (उर्फ टेबल प्रति टाइप इनहेरिटेंस):
यह वह उपाय है जो @David दूसरे उत्तर में उल्लेख करता है । आप अपने बेस क्लास के लिए एक एकल तालिका बनाते हैं, जिसमें सभी सामान्य विशेषताएँ शामिल हैं। फिर आप प्रत्येक उपप्रकार के लिए विशिष्ट तालिकाएँ बनाएंगे, जिनकी प्राथमिक कुंजी भी आधार तालिका के लिए एक विदेशी कुंजी के रूप में कार्य करती है । उदाहरण:
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)
);
यह समाधान अन्य दो डिज़ाइनों में पहचानी गई समस्याओं को हल करता है:
अनिवार्य विशेषताओं के साथ लागू किया जा सकता है NOT NULL
।
एक नया उपप्रकार जोड़ने के लिए एक मौजूदा एक में कॉलम जोड़ने के बजाय एक नई तालिका जोड़ना आवश्यक है।
कोई जोखिम नहीं है कि एक अनुचित विशेषता एक विशेष उपप्रकार के लिए निर्धारित है।
type
विशेषता के लिए कोई ज़रूरत नहीं है ।
अब आम विशेषताओं को उप-प्रकार विशिष्ट विशेषताओं के साथ अब और नहीं मिलाया जाता है।
हम अंत में DRY रह सकते हैं। तालिकाओं को बनाते समय प्रत्येक उपप्रकार तालिका के लिए सामान्य विशेषताओं को दोहराने की आवश्यकता नहीं है।
id
नीतियों के लिए एक ऑटो वेतन वृद्धि का प्रबंधन करना आसान हो जाता है, क्योंकि इसे स्वतंत्र रूप से उत्पन्न करने वाली प्रत्येक उपप्रकार तालिका के बजाय बेस टेबल द्वारा नियंत्रित किया जा सकता है।
उपप्रकार की परवाह किए बिना सभी नीतियों के लिए खोज करना अब बहुत आसान हो गया है: कोई UNION
ज़रूरत नहीं है - बस एक SELECT * FROM policies
।
मैं क्लास टेबल के दृष्टिकोण को ज्यादातर स्थितियों में सबसे उपयुक्त मानता हूं।
इन तीनों मॉडलों के नाम मार्टिन फाउलर की पुस्तक पैटर्न ऑफ एंटरप्राइज एप्लीकेशन आर्किटेक्चर से आए हैं ।