@Bill Karwin ने SQL Entity-Attribute-Value antipattern के समाधान का प्रस्ताव देते समय अपनी 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
enforce को भी लागू नहीं कर सकते हैं एक उपप्रकार की विशेषताओं पर जो अनिवार्य होना चाहिए। आपको इसे अपने आवेदन में संभालना होगा, जो सामान्य रूप से आदर्श नहीं है।
ठोस तालिका वंशानुक्रम:
वंशानुक्रम से निपटने का एक अन्य तरीका प्रत्येक उपप्रकार के लिए एक नई तालिका बनाना है, प्रत्येक तालिका में सभी सामान्य विशेषताओं को दोहराना। उदाहरण के लिए:
--// 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
with के साथ लागू किया जा सकता है । -
एक नया उपप्रकार जोड़ने के लिए मौजूदा तालिका में कॉलम जोड़ने के बजाय एक नई तालिका जोड़ने की आवश्यकता होती है।
-
इस बात का भी कोई जोखिम नहीं है कि किसी विशेष उपप्रकार के लिए एक अनुपयुक्त विशेषता सेट की गई है, जैसे कि
vehicle_reg_no
संपत्ति नीति के लिए फ़ील्ड। -
type
. की कोई आवश्यकता नहीं है एकल तालिका विधि के रूप में विशेषता। प्रकार अब मेटाडेटा द्वारा परिभाषित किया गया है:तालिका का नाम।
हालांकि इस मॉडल के कुछ नुकसान भी हैं:
-
सामान्य विशेषताएँ उपप्रकार विशिष्ट विशेषताओं के साथ मिश्रित होती हैं, और उन्हें पहचानने का कोई आसान तरीका नहीं है। डेटाबेस को भी पता नहीं चलेगा।
-
तालिकाओं को परिभाषित करते समय, आपको प्रत्येक उपप्रकार तालिका के लिए सामान्य विशेषताओं को दोहराना होगा। यह निश्चित रूप से सूखा नहीं है।
-
उपप्रकार की परवाह किए बिना सभी नीतियों को खोजना मुश्किल हो जाता है, और इसके लिए
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
s की आवश्यकता है - बस एकSELECT * FROM policies
।
मैं कक्षा तालिका दृष्टिकोण को अधिकांश स्थितियों में सबसे उपयुक्त मानता हूँ।
इन तीन मॉडलों के नाम मार्टिन फाउलर की पुस्तक पैटर्न्स ऑफ एंटरप्राइज एप्लीकेशन आर्किटेक्चर से लिए गए हैं।