डेटाबेस के लिए रिलेशनल मॉडल क्यों मायने रखता है?


61

मैं एक परियोजना के लिए आ रहा हूँ जहाँ मुझे अपने बॉस के साथ एक डेटाबेस को लागू करना होगा; हम एक बहुत छोटी शुरुआत कर रहे हैं ताकि काम का माहौल गहरा व्यक्तिगत हो।

उन्होंने मुझे पहले कंपनी डेटाबेस में से एक दिया था और यह पूरी तरह से आरडीबीएमएस के लिए स्कूल में मुझे पढ़ाया गया (और पढ़ा गया) के खिलाफ गया था। उदाहरण के लिए, यहां पूरे डेटाबेस हैं जिनमें एक तालिका (प्रति स्वतंत्र डेटाबेस) शामिल है। उन तालिकाओं में से एक 20+ कॉलम लंबा है और संदर्भ के लिए, यहां एक तालिका से कुछ स्तंभ नाम दिए गए हैं :

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName

मुद्दा यह है कि जहां उसके पास व्यक्तिगत तालिकाओं होनी चाहिए, जो इकाई डेटा (नाम, आकार, खरीदी गई तारीख, आदि) रखती है। वह प्रति डेटाबेस एक बड़ी तालिका में यह सब बताती है।

मैं इस डिज़ाइन में सुधार करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि एक ठीक-सामान्य और खंडित डेटा मॉडल वास्तव में इस उत्पाद को बेहतर क्यों बनाएगा। जबकि मैं कॉलेज से डेटाबेस डिजाइन से परिचित हूं और मैं समझता हूं कि यह कैसे करना है, मैं अनिश्चित हूं कि यह वास्तव में डेटाबेस में सुधार क्यों करता है।

एक अच्छा संबंधपरक स्कीमा एक डेटाबेस में सुधार क्यों करता है?


33
एक शब्द: सामान्यीकरण।
रॉबर्ट हार्वे

9
बंद मतदाता - अपने आप को औचित्य दें! :-)
रॉबी डी

6
नए कर्मचारियों के लिए उनके पीछे के कारणों को समझे बिना स्थापित प्रक्रियाओं की आलोचना करना आम बात है, भले ही वे कारण तकनीकी रूप से सही न हों। पहले पता करें कि आपके बॉस ने इसे इस तरह से क्यों बनाया है। वह / वह बहुत अच्छी तरह से जान सकते हैं कि यह एक अच्छा डिज़ाइन नहीं है, लेकिन इसे बेहतर करने के लिए ज्ञान (या अधिक संभावना, समय) नहीं है। आपके द्वारा प्रस्तावित कोई भी परिवर्तन संभवतः सकारात्मक रूप से प्राप्त होगा यदि आप वर्तमान डिजाइन के कारणों को सम्मानपूर्वक स्वीकार करते हैं।
पेड्रो

5
He [the boss] had given me one of his databases before and it completely went against what I was taught (and read about) in school for RDBMS<- वास्तविक दुनिया में आपका स्वागत है!
मौज

5
मुझे अपने पसंदीदा संबंधपरक डेटाबेस उद्धरण की याद दिलाई गई है: "सामान्य रूप से टिल करें, इससे दर्द होता है, टिल को यह काम करता है"
जेक

जवाबों:


70

प्रदर्शन तर्क आमतौर पर वह है जो सबसे अधिक सहज है। आप विशेष रूप से इंगित करना चाहते हैं कि गलत तरीके से सामान्यीकृत डेटाबेस में अच्छे अनुक्रमों को कैसे जोड़ना मुश्किल होगा (ध्यान दें: ऐसे किनारे-मामले हैं जहां वास्तव में प्रदर्शन में सुधार हो सकता है , लेकिन जब आप दोनों संबंधपरक डेटाबेस के साथ अनुभवहीन होते हैं, तो आप आसानी से संभावना करेंगे इन मामलों को देखें)।

एक अन्य भंडारण आकार तर्क है। अतिरेक के साथ एक अपभ्रंश तालिका में कहीं अधिक भंडारण की आवश्यकता होगी। यह प्रदर्शन पहलू में भी खेलता है: आपके पास जितना अधिक डेटा होगा, आपके प्रश्नों को उतना ही धीमा किया जाएगा।

एक तर्क भी है जिसे समझना थोड़ा कठिन है, लेकिन वास्तव में यह अधिक महत्वपूर्ण है क्योंकि आप इसे अधिक हार्डवेयर फेंककर हल नहीं कर सकते। यह डेटा संगतता समस्या है। एक ठीक से सामान्यीकृत डेटाबेस अपने आप ही ध्यान रखेगा कि एक विशिष्ट आईडी वाले उत्पाद का हमेशा एक ही नाम होता है। लेकिन एक विकृत डेटाबेस में ऐसी विसंगतियां संभव हैं, इसलिए विसंगतियों से बचने के लिए विशेष देखभाल की आवश्यकता होती है, जो सही होने के लिए प्रोग्रामिंग समय लेगी और अभी भी बग का कारण बनेगी जो आपको ग्राहकों की संतुष्टि में खर्च करेगी।


19
वनीकरण के लिए एक प्रमुख धार मामला डेटा वेयरहाउसिंग है , विशेष रूप से, यदि आपके पास बड़ी मात्रा में डेटा है जिसे कभी भी बदलने की गारंटी नहीं है और आप भंडारण स्थान की कीमत पर इसे और अधिक तेज़ी से और कुशलता से क्वेरी करना चाहते हैं। अच्छा जवाब, यह किसी भी SQL newbies के लिए सिर्फ एक FYI है, जो सुनिश्चित नहीं हैं कि 3NF के अलावा कुछ भी वांछनीय क्यों होगा।


11
मुझे यकीन नहीं है कि संगतता तर्क "समझने में कठिन है।" यह मुझे बहुत सरल लगता है: यदि कोई मूल्य बदलता है, तो उस मूल्य की सभी प्रतियां अपडेट होनी चाहिए। एक ही प्रति अपडेट करना एक ही डेटा की सैकड़ों या हजारों प्रतियों को अपडेट करने की तुलना में बहुत कम त्रुटि वाला है। यह डेटा के बीच संबंधों पर समान रूप से लागू होता है । (यदि मेरे पास संबंध दो तरीके से संग्रहीत हैं, तो मुझे रिश्ते की दोनों प्रतियों को अपडेट करना होगा।) यह असामान्य डीबी में एक अत्यंत सामान्य समस्या है; यह बहुत (एक अपवाद दृश्य प्रकार उपयोग materialized है) व्यवहार में इस भ्रष्टाचार को रोकने के लिए मुश्किल।
jpmc26

4
उस आखिरी पैराग्राफ को बोल्ड में हाइलाइट किया जाना चाहिए। :-) सामान्यीकरण के बिना डेटा अखंडता की गारंटी देना असंभव है। पूरी तरह से व्यापार तर्क परत पर इनपुट को नियंत्रित करना एक मूर्खतापूर्ण कार्य है क्योंकि प्रत्येक गैर-सामान्यीकृत डेटाबेस अंततः किसी प्रकार के डेटा विसंगति को प्रदर्शित करता है।
DanK

2
@IsmaelMiguel सामान्य अभ्यास यह है कि इस तरह का मास्टर-डेटा डेटाबेस से कभी हार्ड-डिलीट नहीं होता है। आप केवल उस पर एक झंडा लगाकर उसे सॉफ्ट-डिलीट कर देते हैं जो कहता है कि यह अब उपलब्ध नहीं है। इस विशेष मामले में उत्पादों और आदेशों के बीच एक विदेशी कुंजी संबंध रखना एक अच्छा विचार होगा जिसका अर्थ है कि जब आप किसी उत्पाद को हटाने का प्रयास करते हैं तो डेटाबेस एक त्रुटि फेंक देगा जो किसी भी आदेश द्वारा संदर्भित है।
फिलिप

24

मुझे अपने बॉस के साथ एक डेटाबेस लागू करना होगा ...

समर्पित डेटाबेस प्रबंधन सॉफ्टवेयर का उपयोग करना काफी आसान हो सकता है (क्षमा करें, विरोध नहीं कर सकता)।

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName

इस डेटाबेस केवल "प्रवेश" जो उत्पाद बेच दिया गया था कहां, कब और किसके द्वारा, तो आप के बारे में परवाह है, तो हो सकता है अब तक इसे कवर करने के लिए पर्याप्त "ठीक डेटाबेस" की परिभाषा खिंचाव करने में सक्षम हो। यदि यह डेटा किसी और चीज़ के लिए उपयोग किया जा रहा है, तो यह वास्तव में बहुत खराब है।

परंतु ...

क्या इस डेटा का उपयोग करने वाले एप्लिकेशन / क्वेरीज़ खराब / धीरे प्रतिक्रिया करते हैं? यदि नहीं, तो हल करने के लिए कोई वास्तविक समस्या नहीं है। ज़रूर, यह बदसूरत दिखता है और महसूस होता है, लेकिन अगर यह काम करता है तो आपको "सुझाव" के लिए कोई "अंक" नहीं मिलने वाला है, यह बेहतर हो सकता है।

यदि आप निश्चित लक्षण (यानी समस्याएं) पा सकते हैं, जैसे कि वे खराब डेटा मॉडलिंग के कारण दिखते हैं, तो एक बेहतर समाधान का प्रोटोटाइप बनाएं। इन "डेटाबेस" में से एक की एक प्रति ले लो, डेटा को सामान्य करें और देखें कि क्या आपका समाधान किसी भी बेहतर चलता है। यदि यह काफी बेहतर है (और मैं पूरी तरह से उम्मीद करूंगा कि इस डेटा पर कोई भी अपडेट ऑपरेशन बड़े पैमाने पर सुधार होगा) तो अपने बॉस पर वापस जाएं और उन्हें सुधार दिखाएं।

यह अच्छी तरह से .. दृश्य के साथ डेटा के अपने "एकल-तालिका दृश्य" को फिर से बनाना संभव है।


11
एकल तालिका weltanschauung का प्रतिरोध अक्सर SQL के साथ अनुभवहीन उन लोगों से आता है जो जुड़ाव को नहीं समझते हैं - विशेष रूप से लापता डेटा यानी बाहरी जुड़ाव के संबंध में।
रॉबी डी

6
@ रॉबीडी अधिक सामान्यतः, यह उन लोगों से है जिन्होंने असमान डेटा देखा है जो असंगत होकर दूषित हो जाते हैं। मैं एक ऐसा व्यक्ति हूं। मैं केवल इस तरह की संरचना पर विचार करूंगा कि स्थिति फिल में बताती है: यह कुछ प्रकार की लॉगिंग / रिपोर्टिंग तालिका है जहां डेटा को कभी भी अपडेट नहीं किया जाएगा या केवल साफ किया जाएगा और अन्य स्रोतों से पूरी तरह से फिर से प्राप्त किया जाएगा।
jpmc26

2
भले ही एप्लिकेशन इस तरह डेटाबेस के साथ स्वीकार्य रूप से प्रदर्शन करता है, यह अभी भी एक सामान्यीकृत डेटाबेस की तरह लचीला नहीं है। यदि स्टोर का नाम या कंपनी का नाम बदल जाता है, तो उसे हर जगह अपडेट करना होगा, बजाय केवल एक स्टोर या कंपनी की तालिका के। कुछ मामलों में, यह वास्तव में वही हो सकता है जो आप चाहते हैं (जैसे कि डेटा को मुख्य रूप से अभिलेखीय उद्देश्यों के लिए एकत्र किया गया है), लेकिन हमें विशिष्ट एप्लिकेशन के बारे में अधिक जानना होगा।
Zach Lipton

1
@Zach: सहमत, इसीलिए बिक्री लॉग संभावित रूप से इसके लिए स्वीकार्य मामला है। यह मानते हुए कि आप चाहते हैं कि बिक्री के समय जो भी दुकान बनाई गई थी, उसका नाम "स्टोर का वर्तमान नाम" न हो, फिर प्रत्येक बिक्री जुड़ी हो , फिर "सामान्यीकरण" करने का प्रयास यह कुछ काफी जटिलता का परिचय देता है (क्योंकि टेबल रिकॉर्डिंग स्टोर के नाम समय के साथ एक श्रृंखला बनाने की आवश्यकता होगी, न कि केवल एक मूल्य प्रति दुकान)
स्टीव जेसप

शायद अंगूठे का एक नियम यह होगा कि यदि प्रस्तावित सामान्यीकरण द्वारा शुरू की गई एकमात्र जटिलता यह है कि अब उन सभी स्तंभों को चुनने के लिए कुछ प्रश्नों की आवश्यकता होती है, जिन्हें आपको रिपोर्ट करने की आवश्यकता है, तो आपको उस परिवर्तन को करने के लिए नहीं चलना चाहिए: - )
स्टीव जेसोप

14

एक अच्छा संबंधपरक स्कीमा एक डेटाबेस में सुधार क्यों करता है?

जवाब है: यह हमेशा एक डेटाबेस में सुधार नहीं करता है। आपको इस बात की जानकारी होनी चाहिए कि आपको जो पढ़ाया जा रहा था, उसे थर्ड नॉर्मल फॉर्म कहा जाता है ।

अन्य रूप कुछ स्थितियों में मान्य हैं, जो आपके प्रश्न का उत्तर देने के लिए महत्वपूर्ण है। आपका उदाहरण फर्स्ट नॉर्मल फॉर्म की तरह दिखता है , अगर यह आपको इसकी वर्तमान स्थिति के बारे में बेहतर महसूस करने में मदद करता है।

3NF नियम एक डेटाबेस में "सुधार" करने वाले डेटा के बीच संबंध स्थापित करते हैं:

  1. अपने सिस्टम में प्रवेश करने से अवैध डेटा को रोकें (यदि कोई संबंध 1 से 1 है तो यह कोड के शीर्ष पर लिखे जाने के बावजूद त्रुटि पैदा करता है)। यदि आपका डेटा डेटाबेस में सुसंगत है, तो इससे आपके डेटाबेस के बाहर विसंगतियों के परिणामस्वरूप होने की संभावना कम है।

  2. यह कोड को मान्य करने का एक तरीका प्रदान करता है (जैसे कई-से-एक संबंध किसी वस्तु के गुणों / व्यवहारों को प्रतिबंधित करने के लिए एक संकेत है)। डेटाबेस का उपयोग करने के लिए कोड लिखते समय, कभी-कभी प्रोग्रामर डेटा संरचना को एक संकेतक के रूप में देखते हैं कि उनके कोड को कैसे काम करना चाहिए। यदि डेटाबेस उनके कोड से मेल नहीं खाता है तो वे उपयोगी प्रतिक्रिया दे सकते हैं। (यह इच्छाधारी सोच की तरह है, दुर्भाग्य से।)

  3. ऐसे नियम प्रदान करें जो डेटाबेस बनाते समय गलतियों को कम करने में आपकी बहुत मदद कर सकते हैं, ताकि आप इसे मनमानी आवश्यकताओं के आधार पर नहीं बना रहे हैं जो डेटाबेस के जीवन के दौरान किसी भी समय आ सकता है। इसके बजाय, आप विशिष्ट लक्ष्यों को प्राप्त करने के लिए व्यवस्थित रूप से जानकारी का मूल्यांकन कर रहे हैं।

  4. उचित डेटाबेस संरचनाएँ डेटा भंडारण को कम करने वाले तरीकों से डेटा को बेहतर बनाने के लिए बेहतर प्रदर्शन की ओर ले जाती हैं, डेटा को पुनः प्राप्त करने के लिए स्टोरेज कॉल्स को कम करते हैं, आपके द्वारा की गई क्वेरी की तुलना में आपके द्वारा प्राप्त विशेष डेटासेट के लिए अधिकतम मेमोरी मेमोरी संसाधनों और / या डेटा सॉर्टिंग / हेरफेर को कम करते हैं। इसके विरुद्ध कार्य करना। लेकिन "उचित" संरचना डेटा की मात्रा, डेटा की प्रकृति, क्वेरी के प्रकार, सिस्टम संसाधन, आदि पर निर्भर करती है। सामान्य करने से आप प्रदर्शन को बदतर बना सकते हैं (यानी यदि आप सभी डेटा को 1 तालिका के रूप में लोड करते हैं - तो जुड़ना धीमा हो सकता है एक प्रश्न)। लेनदेन प्रसंस्करण (ओएलटीपी) बनाम व्यापार खुफिया (डेटा वेयरहाउस) बहुत अलग हैं।

छोटे डेटा सेट के साथ एक छोटी सी कंपनी में, आप पा सकते हैं कि जिस तरह से यह अब है उसमें कुछ भी गलत नहीं है। सिवाय, यदि आप बढ़ते हैं, तो यह बाद में "ठीक" करने के लिए एक दर्द होगा, क्योंकि जैसे ही मेज बड़ी हो जाती है, सिस्टम जो इसका उपयोग करते हैं वे संभवतः धीमी हो जाएंगे।

आमतौर पर आप तेजी से लेनदेन पर जोर देना चाहेंगे क्योंकि कंपनी बढ़ती है। हालाँकि, यदि आप इस परियोजना पर अब अन्य चीजों के बजाय समय बिताते हैं, जिसकी कंपनी को और अधिक आवश्यकता हो सकती है, तो आपको कभी भी यह समस्या नहीं हो सकती है क्योंकि आपकी कंपनी वास्तव में कभी नहीं बढ़ती है। यह "पूर्व-अनुकूलन चुनौती" है - जहां अभी अपना कीमती समय बिताना है।

सौभाग्य!


4
असंबद्ध लेकिन मुझे लगता है कि प्रोग्रामरों के लिए एक महत्वपूर्ण बिंदु यह है कि एक "चीज़" को संपादित करने के लिए उस एकल चीज़ को खोजने और बदलने के लिए पूरे डेटाबेस को लूप करने के बजाय केवल एक ही पंक्ति के संपादन की आवश्यकता होती है।
स्लीपबेटमैन

@slebetman आपके पास एक कोड टेबल में एक पंक्ति में कई पंक्तियों को अपडेट करने के लिए कभी भी कोड साइड लूप नहीं होना चाहिए, चाहे वह सामान्यीकृत क्यों न हो। एक WHEREक्लॉज का उपयोग करें । बेशक, ये अभी भी गलत हो सकते हैं, लेकिन सामान्य स्थिति में इसकी संभावना कम है क्योंकि आपको केवल प्राथमिक कुंजी के माध्यम से एक पंक्ति से मेल खाना है।
jpmc26

@ jpmc26: डेटाबेस को लूप करने से मेरा मतलब है कि सभी प्रभावित पंक्तियों को अपडेट करने के लिए एक क्वेरी का निर्माण करना। कभी-कभी एक ही जहाँ पर्याप्त होता है। लेकिन मैंने ऐसी अपवित्र संरचनाएँ देखी हैं, जिन्हें बदलने की पंक्तियों को प्रभावित किए बिना सभी प्रभावित पंक्तियों को प्राप्त करने के लिए एक ही तालिका में subselects की आवश्यकता होती है। मैंने ऐसी संरचनाएँ भी देखी हैं जहाँ एक भी क्वेरी काम नहीं कर सकती है (जिस इकाई को परिवर्तन की आवश्यकता होती है वह पंक्ति के आधार पर अलग-अलग कॉलम में रहती है)
स्लीवेटमैन

इस प्रश्न के कई उत्कृष्ट उत्तर, और यह कोई अपवाद नहीं था।
माइक चेम्बरलेन

11

एक बड़े "भगवान की मेज" का उपयोग करने के कई कारण खराब हैं। मैं कोशिश करता हूँ और एक उदाहरण डेटाबेस के साथ समस्याओं का वर्णन करता हूँ। मान लेते हैं कि आप खेल स्पर्धाओं को मॉडल बनाने की कोशिश कर रहे हैं। हम कहेंगे कि आप खेलों और उन खेलों में खेलने वाली टीमों को मॉडल बनाना चाहते हैं। कई तालिकाओं के साथ एक डिजाइन इस तरह दिख सकता है (यह उद्देश्य पर बहुत सरल है, इसलिए उन जगहों पर नहीं पकड़ा जाना चाहिए जहां अधिक सामान्यीकरण लागू किया जा सकता है):

Teams
Id | Name | HomeCity

Games
Id | StartsAt | HomeTeamId | AwayTeamId | Location

और एक एकल तालिका डेटाबेस इस तरह दिखेगा

TeamsAndGames
Id | TeamName | TeamHomeCity | GameStartsAt | GameHomeTeamId | GameAwayTeamId | Location

सबसे पहले, आइए उन तालिकाओं पर सूचकांक बनाते हुए देखें। अगर मुझे टीम के लिए होम सिटी पर एक इंडेक्स की जरूरत है, तो मैं इसे Teamsटेबल या TeamsAndGamesटेबल पर आसानी से जोड़ सकता हूं । याद रखें कि जब भी आप कोई इंडेक्स बनाते हैं, तो उसे कहीं न कहीं डिस्क पर स्टोर करना पड़ता है और टेबल पर पंक्तियों को जोड़कर अपडेट किया जाता है। Teamsतालिका के मामले में यह बहुत सीधा है। मैंने एक नई टीम में रखा, डेटाबेस इंडेक्स को अपडेट करता है। लेकिन किस लिए TeamsAndGames? ठीक है, एक ही से लागू होता हैTeamsउदाहरण। मैं एक टीम जोड़ता हूं, सूचकांक अपडेट हो जाता है। लेकिन यह भी होता है जब मैं एक खेल जोड़ता हूं! भले ही वह क्षेत्र किसी गेम के लिए शून्य हो, फिर भी इंडेक्स को उस गेम के लिए डिस्क पर अपडेट और स्टोर किया जाना है। एक सूचकांक के लिए, यह बहुत बुरा नहीं है। लेकिन जब आपको इस तालिका में शामिल कई संस्थाओं के लिए कई सूचकांकों की आवश्यकता होती है, तो आप सूचक को संग्रहीत करने के लिए बहुत सारे स्थान बर्बाद करते हैं और बहुत से प्रोसेसर समय उन चीजों के लिए अपडेट करते हैं जहां वे लागू नहीं होते हैं।

दूसरा, डेटा संगति। दो अलग-अलग तालिकाओं का उपयोग करने के मामले में, मैं यह परिभाषित Gamesकरने के लिए Teamsतालिका से टेबल पर विदेशी कुंजियों का उपयोग कर सकता हूं कि कौन सी टीम खेल में खेल रही है। और यह मानते हुए कि मैं HomeTeamIdऔर AwayTeamIdस्तम्भों को अशक्त नहीं बनाता , डेटाबेस यह सुनिश्चित करेगा कि मेरे द्वारा लगाए गए हर खेल में 2 टीमें हों और वे टीमें मेरे डेटाबेस में मौजूद हों। लेकिन एकल तालिका परिदृश्य के बारे में क्या? खैर, चूंकि इस तालिका में कई इकाइयां हैं, इसलिए उन स्तंभों को अशक्त होना चाहिए (आप उन्हें अशक्त नहीं कर सकते और कचरा डेटा को वहां भेज सकते हैं, लेकिन यह सिर्फ एक भयानक विचार है)। यदि वे कॉलम अशक्त हैं, तो डेटाबेस अब यह गारंटी नहीं दे सकता है कि जब आप कोई गेम डालें तो उसमें दो टीमें हों।

लेकिन क्या होगा अगर आप वैसे भी इसके लिए जाने का फैसला करते हैं? आप विदेशी कुंजियों को सेट करते हैं, जैसे कि फ़ील्ड उसी तालिका में किसी अन्य इकाई पर वापस जाती हैं। लेकिन अब डेटाबेस केवल यह सुनिश्चित करेगा कि उन संस्थाओं की तालिका में मौजूद हैं, न कि वे सही प्रकार हैं। आप बहुत आसानी GameHomeTeamIdसे किसी अन्य गेम की आईडी पर सेट हो सकते हैं और डेटाबेस बिल्कुल भी शिकायत नहीं करेगा। यदि आपने कोशिश की कि एकाधिक तालिका परिदृश्य में, डेटाबेस एक फिट फेंक देगा।

आप इन मुद्दों को "ठीक है, हम कह सकते हैं कि हम यह सुनिश्चित करेंगे कि हम कोड में कभी ऐसा न करें"। यदि आप पहली बार बग फ्री कोड लिखने की अपनी क्षमता पर विश्वास कर रहे हैं और उपयोगकर्ता द्वारा कोशिश की जा सकने वाली चीजों के हर अजीब संयोजन को ध्यान में रखने की आपकी क्षमता है, तो ठीक है। मैं व्यक्तिगत रूप से उन दोनों चीजों को करने की अपनी क्षमता में विश्वास नहीं कर रहा हूं, इसलिए मैं डेटाबेस को मुझे एक अतिरिक्त सुरक्षा जाल दूंगा।

(यह तब और भी बदतर हो जाता है जब आपका डिज़ाइन वह होता है जहां आप विदेशी कुंजियों का उपयोग करने के बजाय पंक्तियों के बीच सभी प्रासंगिक डेटा को कॉपी करते हैं। किसी भी वर्तनी / अन्य डेटा असंगतता को हल करना मुश्किल होगा। आप कैसे बता सकते हैं कि "जॉन" जॉन की गलत वर्तनी है। "या अगर यह जानबूझकर था (क्योंकि वे दो अलग-अलग लोग हैं)?"

तीसरा, लगभग हर स्तंभ को अशक्त होने की आवश्यकता है या उसे कॉपी किए गए या कचरा डेटा से भरा होना चाहिए। एक खेल एक की जरूरत नहीं है TeamNameया TeamHomeCity। तो या तो हर खेल को वहां किसी प्रकार के प्लेसहोल्डर की जरूरत होती है या उसे अशक्त होने की जरूरत होती है। और अगर यह अशक्त है, तो डेटाबेस ख़ुशी के साथ कोई खेल लेगा TeamName। यह बिना नाम वाली टीम भी लेगा, भले ही आपका व्यवसाय तर्क कहता हो कि ऐसा कभी नहीं होना चाहिए।

वहाँ कुछ अन्य कारण हैं कि आप अलग-अलग तालिकाओं को क्यों विकसित करना चाहते हैं (जिसमें विकासकर्ता संन्यास भी शामिल है)। यहां तक ​​कि कुछ कारण भी हैं कि एक बड़ी तालिका बेहतर हो सकती है (पुनरावृत्ति कभी-कभी प्रदर्शन में सुधार करती है)। उन परिदृश्यों के बीच कुछ और दूर हैं (और आमतौर पर सबसे अच्छा संभाला जाता है जब आपके पास प्रदर्शन मैट्रिक्स है यह दिखाने के लिए कि यह वास्तव में समस्या है, लापता सूचकांक या कुछ और नहीं)।

अंत में, कुछ ऐसा विकसित करें जिसे बनाए रखना आसान होगा। सिर्फ इसलिए कि यह "काम करता है" इसका मतलब यह नहीं है कि यह ठीक है। भगवान की मेज (जैसे देव वर्गों) को बनाए रखने की कोशिश एक बुरा सपना है। आप बस बाद में दर्द के लिए खुद को स्थापित कर रहे हैं।


1
"टीम: आईडी | नाम | होमसिटी"। बस सुनिश्चित करें कि आपका डेटा स्कीमा आपके आवेदन को गलत तरीके से दावा नहीं करता है कि एलए राम द्वारा सुपर बाउल XXXIV जीता गया था। जबकि SB XXXIV को वर्तमान में LA Rams के रूप में जानी जाने वाली टीम द्वारा जीती गई सभी चैंपियनशिप के लिए एक क्वेरी में दिखना चाहिए । बेहतर और बदतर "भगवान की मेज" हैं, और आपने निश्चित रूप से एक बुरा प्रस्तुत किया है। एक बेहतर होगा "गेम आईडी। होम टीम का नाम | होम टीम शहर | दूर टीम का नाम | दूर टीम शहर | खेल शुरू होता है आदि ..."। जो कि "न्यू ऑरलियन्स सेंट्स @ शिकागो बियर 1 पी ईस्टर्न" जैसी जानकारी के लिए पहले प्रयास के रूप में आता है।
स्टीव जेसोप २ Steve

6

दिन का उद्धरण: " सिद्धांत में सिद्धांत और व्यवहार समान होना चाहिए ... "

असामान्य तालिका

आपकी अद्वितीय होल्ड-इट-ऑल टेबल में निरर्थक डेटा शामिल हैं, इसका एक फायदा है: यह अपनी लाइनों पर रिपोर्टिंग को कोड करने के लिए बहुत सरल बनाता है और निष्पादित करने के लिए तेज़ होता है क्योंकि आपको कोई जॉइन नहीं करना है। लेकिन यह एक उच्च लागत पर:

  • यह संबंधों की बेमानी प्रतियाँ रखता है (जैसे IngCompanyIDऔर vrCompanyName)। मास्टर डेटा को अपडेट करने के लिए सामान्यीकृत स्कीमा की तुलना में कई और लाइनों को अपडेट करना पड़ सकता है।
  • यह सब कुछ मिलाता है। आप डेटाबेस स्तर पर एक आसान पहुँच नियंत्रण सुनिश्चित नहीं कर सकते हैं, उदाहरण के लिए यह सुनिश्चित करना कि उपयोगकर्ता A केवल कंपनी की जानकारी, और उपयोगकर्ता B केवल उत्पाद जानकारी को अपडेट कर सकता है।
  • आप डेटाबेस स्तर पर संगतता नियम सुनिश्चित नहीं कर सकते (उदाहरण के लिए प्राथमिक कुंजी लागू करने के लिए कि कंपनी आईडी के लिए केवल एक कंपनी का नाम है)।
  • आप DB ऑप्टिमाइज़र से पूरी तरह से लाभान्वित नहीं होते हैं जो एक जटिल क्वेरी के लिए इष्टतम पहुंच रणनीतियों की पहचान कर सकता है, सामान्यीकृत तालिकाओं के आकार और कई अनुक्रमित के आंकड़ों का लाभ उठा सकता है। यह जल्दी से जुड़ने से बचने के सीमित लाभ को ऑफसेट कर सकता है।

सामान्यीकृत तालिका

उपरोक्त नुकसान सामान्यीकृत स्कीमा के लिए फायदे हैं। बेशक, प्रश्न लिखने के लिए थोड़ा अधिक जटिल हो सकते हैं।

संक्षेप में, सामान्यीकृत स्कीमा आपके डेटा के बीच संरचना और संबंधों को बेहतर ढंग से व्यक्त करता है। मैं उत्तेजक होऊंगा और कहूंगा कि ऑर्डर किए गए ऑफिस ड्रॉअर के सेट और ट्रैश बिन के उपयोग में आसानी के बीच अनुशासन की तुलना में यह उसी तरह का अंतर है।


5

मुझे लगता है कि आपके प्रश्न के कम से कम दो भाग हैं:

1. विभिन्न प्रकार की संस्थाओं को एक ही तालिका में संग्रहीत क्यों नहीं किया जाना चाहिए?

यहां सबसे महत्वपूर्ण उत्तर कोड पठनीयता और गति हैं। ए SELECT name FROM companies WHERE id = ?सिर्फ एक की तुलना में बहुत अधिक पठनीय है SELECT companyName FROM masterTable WHERE companyId = ?और आप गलती से बकवास करने की संभावना कम हैं (जैसे SELECT companyName FROM masterTable WHERE employeeId = ?कि कंपनियों और कर्मचारियों को अलग-अलग तालिकाओं में संग्रहीत किए जाने पर संभव नहीं होगा)। गति के लिए, डेटाबेस तालिका से डेटा या तो पूर्ण तालिका को क्रमिक रूप से पढ़कर, या एक सूचकांक से पढ़कर प्राप्त किया जाता है। यदि तालिका / अनुक्रमणिका में डेटा कम है, और डेटा भिन्न तालिकाओं में संग्रहीत है (और आपको केवल तालिका / सूचकांकों में से किसी एक को पढ़ने की आवश्यकता है) तो दोनों ही तेज़ हैं।

2. एक ही प्रकार की संस्थाओं को अलग-अलग तालिकाओं में संग्रहीत उप-संस्थाओं में क्यों विभाजित किया जाना चाहिए?

यहां, कारण ज्यादातर डेटा असंगतियों को रोकने के लिए है। एकल तालिका दृष्टिकोण के साथ, एक आदेश प्रबंधन प्रणाली के लिए आप ग्राहक का नाम, ग्राहक पता और उत्पाद की उत्पाद आईडी को संग्रहीत कर सकते हैं, जिसे ग्राहक एक एकल इकाई के रूप में ऑर्डर करता है। यदि किसी ग्राहक ने कई उत्पादों का आदेश दिया है, तो आपके डेटाबेस में ग्राहक के नाम और पते के कई उदाहरण होंगे। सबसे अच्छी स्थिति में, आपको बस अपने डेटाबेस में डुप्लिकेट डेटा मिला, जो इसे थोड़ा धीमा कर सकता है। लेकिन इससे भी बदतर मामला यह है कि किसी (या कुछ कोड) ने गलती की थी जब डेटा दर्ज किया गया था ताकि आपके डेटाबेस में विभिन्न पते के साथ एक कंपनी समाप्त हो जाए। यह अकेला ही काफी खराब है। लेकिन अगर आप किसी कंपनी के पते को उसके नाम के आधार पर क्वेरी करना चाहते हैं (जैसेSELECT companyAddress FROM orders WHERE companyName = ? LIMIT 1) आप मनमाने ढंग से दो पते में से एक को लौटा देंगे और यह भी महसूस नहीं करेंगे कि असंगति थी। लेकिन हर बार जब आप क्वेरी चलाते हैं तो आपको वास्तव में एक अलग पता मिल सकता है, यह इस बात पर निर्भर करता है कि DBMS द्वारा आंतरिक रूप से आपकी क्वेरी को कैसे हल किया जाता है। यह संभवतः आपके आवेदन को कहीं और तोड़ देगा, और उस टूटने का मूल कारण खोजना बहुत कठिन होगा।

मल्टी-टेबल दृष्टिकोण के साथ, आपको पता चलेगा कि कंपनी के नाम से लेकर कंपनी के पते तक एक कार्यात्मक निर्भरता है (यदि कंपनी का केवल एक ही पता हो सकता है), तो आप एक तालिका में कंपनी (CompanyName, companyAddress) टपल को संग्रहीत करेंगे (जैसे company), और (productId, companyName) एक अन्य तालिका (जैसे order) में टपल । टेबल UNIQUEपर एक बाधा companyतब लागू हो सकती है कि प्रत्येक कंपनी के पास आपके डेटाबेस में केवल एक ही पता हो ताकि कंपनी के पते के लिए कोई असंगति कभी उत्पन्न न हो सके।

नोट: व्यवहार में, प्रदर्शन कारणों से आप संभवतः प्रत्येक कंपनी के लिए एक अद्वितीय companyId जनरेट करेंगे और सीधे companyName का उपयोग करने के बजाय इसे विदेशी कुंजी के रूप में उपयोग करेंगे। लेकिन सामान्य दृष्टिकोण वही रहता है।


3

टीएल; डीआर - वे डेटाबेस को डिज़ाइन कर रहे हैं कि वे स्कूल में होने पर उन्हें कैसे सिखाया गया था।

यह सवाल मैं 10 साल पहले लिख सकता था। मुझे यह समझने में कुछ समय लगा कि मेरे पूर्ववर्तियों ने अपने डेटाबेस को जिस तरह से बनाया था, उसे क्यों बनाया। आप किसी ऐसे व्यक्ति के साथ काम कर रहे हैं जो या तो:

  1. एक्सेल का उपयोग कर डेटाबेस या
  2. जब वे स्कूल से बाहर निकले, तो वे सबसे अच्छे अभ्यासों का उपयोग कर रहे थे।

मुझे संदेह नहीं है कि यह # 1 है क्योंकि आपके पास वास्तव में आपकी तालिका में आईडी नंबर हैं, इसलिए मैं # 2 मानूंगा।

स्कूल से बाहर निकलने के बाद, मैं एक ऐसी दुकान के लिए काम कर रहा था जिसमें AS / 400 (उर्फ IBM i) का इस्तेमाल किया गया था । मुझे उनके डेटाबेस को डिजाइन करने के तरीके में कुछ अजीब चीजें मिलीं, और हमने वकालत करना शुरू कर दिया कि हम कैसे डेटाबेस को डिज़ाइन करने के तरीके सिखाए जाते हैं। (मैं तब गूंगा था)

यह एक रोगी वृद्ध प्रोग्रामर ले गया, जो मुझे समझा रहा था कि चीजें इस तरह से क्यों की गईं। उन्होंने स्कीमा को नहीं बदला था क्योंकि इससे ऐसे कार्यक्रम बन जाते थे जो मुझसे पुराने थे। वस्तुतः, मेरे जन्म से पहले एक कार्यक्रम के स्रोत कोड की निर्माण तिथि थी। जिस सिस्टम पर हम काम कर रहे थे, उनके कार्यक्रमों में उन सभी तर्कों और कार्यों को लागू करना था जो आपके डेटाबेस के क्वेरी प्लानर आपके लिए संभालते हैं। (आप अपने प्रश्नों में से एक पर चलकर देख सकते हैं)

वह उन तकनीकों पर अप-टू-डेट थी जिन्हें मैं लागू करने की कोशिश कर रहा था, लेकिन सिस्टम को चालू रखना परिवर्तन बनाने से ज्यादा महत्वपूर्ण था "क्योंकि यह मेरे द्वारा सिखाई गई बातों के विपरीत था"। हम में से हर नए प्रोजेक्ट ने रिलेशनल मॉडल का सबसे अच्छा उपयोग करना शुरू किया, जो हम करने में सक्षम थे। दुर्भाग्य से, उस समय के अन्य प्रोग्रामर / सलाहकारों ने अभी भी अपने डेटाबेस को इस तरह डिज़ाइन किया था जैसे कि वे उस प्रणाली के पूर्व बाधाओं के साथ काम कर रहे हों।


मेरे द्वारा सामना किए गए कुछ उदाहरण जो संबंधपरक मॉडल के लिए उपयुक्त नहीं थे:

  • तिथियों को जूलियन दिन संख्याओं के रूप में संग्रहीत किया गया था, जो वास्तविक तिथि प्राप्त करने के लिए एक तारीख तालिका में शामिल होने की आवश्यकता थी।
  • समान प्रकार (जैसे code1,code2, ..., code20) के अनुक्रमिक स्तंभों के साथ असामान्य तालिकाओं
  • NxM लंबाई CHAR कॉलम M की लंबाई N के तारों की एक सरणी का प्रतिनिधित्व करती है।

जिन कारणों से मुझे उन डिज़ाइन निर्णयों के लिए दिया गया था वे सभी सिस्टम की बाधाओं पर आधारित थे जब डेटाबेस पहली बार डिज़ाइन किया गया था।

तिथियां - मुझे बताया गया था कि तारीखों के कार्यों (जो महीने या दिन या सप्ताह के दिन) का उपयोग करने के लिए अधिक प्रसंस्करण समय लिया गया था, उस तारीख को संसाधित करने के लिए जितना संभव हो, उस सभी सूचनाओं के साथ हर संभव तारीख की तालिका बनाने के लिए।

एक ही प्रकार के अनुक्रमिक कॉलम - प्रोग्रामिंग वातावरण जो उन्हें पंक्ति के भाग पर एक सरणी चर बनाने के लिए एक कार्यक्रम की अनुमति देता था। और यह पढ़ने के संचालन की संख्या को कम करने का एक आसान तरीका था।

NxM लंबाई CHAR कॉलम - फ़ाइल रीड ऑपरेशंस को कम करने के लिए कॉन्फ़िगरेशन कॉलम को एक कॉलम में बदलना आसान था।

सी में एक खराब कल्पना की गई उदाहरण उनके द्वारा किए गए प्रोग्रामिंग वातावरण को प्रतिबिंबित करने के लिए बराबर है:

#define COURSE_LENGTH 4
#define NUM_COURSES 4
#define PERIOD_LENGTH 2

struct mytable {
    int id;
    char periodNames[NUM_COURSES * PERIOD_LENGTH];  // NxM CHAR Column
    char course1[COURSE_LENGTH];
    char course2[COURSE_LENGTH];
    char course3[COURSE_LENGTH];
    char course4[COURSE_LENGTH];
};

...

// Example row
struct mytable row = {.id= 1, .periodNames="HRP1P2P8", .course1="MATH", .course2="ENGL", .course3 = "SCI ", .course4 = "READ"};

char *courses; // Pointer used to access the sequential columns
courses = (char *)&row.course1;


for(int i = 0; i < NUM_COURSES; i++) {

    printf("%d: %.*s -> %.*s\n",i+1, PERIOD_LENGTH, &row.periodNames[PERIOD_LENGTH * i], COURSE_LENGTH,&courses[COURSE_LENGTH*i]);
}

आउटपुट

1: HR -> MATH
2: P1 -> ENGL
3: P2 -> SCI
4: P8 -> READ

मुझे जो बताया गया था, उसके अनुसार, इस समय कुछ को सबसे अच्छा अभ्यास माना जाता था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.