SQL सर्वर डेटाबेस में एकल पंक्ति कॉन्फ़िगरेशन तालिका का उपयोग करना। बुरा विचार?


145

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

रिलेशनल डेटाबेस सिस्टम में सिंगल रो को स्टोर करने के लिए टेबल बनाना बेहद अनुचित लगता है।

इस जानकारी को संग्रहीत करने का उपयुक्त तरीका क्या है?

नोट: मेरा DBMS SQL सर्वर 2008 है और प्रोग्रामिंग लेयर ASP.NET (C # में) के साथ लागू किया गया है।

जवाबों:


189

मैंने अतीत में यह दो तरीके किए हैं - एक एकल पंक्ति तालिका और एक कुंजी / मूल्य जोड़ी तालिका - और प्रत्येक दृष्टिकोण के लिए सकारात्मक और नकारात्मक हैं।

एक पंक्ति

  • सकारात्मक: मान सही प्रकार में संग्रहीत होते हैं
  • सकारात्मक: कोड से निपटना आसान है (उपरोक्त के कारण)
  • सकारात्मक: डिफ़ॉल्ट मान प्रत्येक सेटिंग को व्यक्तिगत रूप से दिया जा सकता है
  • नकारात्मक: एक नई सेटिंग जोड़ने के लिए एक स्कीमा परिवर्तन की आवश्यकता होती है
  • नकारात्मक: यदि बहुत सारी सेटिंग्स हैं, तो तालिका बहुत विस्तृत हो सकती है

कुंजी / मूल्य जोड़ी

  • सकारात्मक: नई सेटिंग्स जोड़ने के लिए एक स्कीमा परिवर्तन की आवश्यकता नहीं होती है
  • सकारात्मक: तालिका स्कीमा संकीर्ण है, नई सेटिंग्स के लिए अतिरिक्त पंक्तियों का उपयोग किया जा रहा है
  • नकारात्मक: प्रत्येक सेटिंग का एक ही डिफ़ॉल्ट मान है (शून्य / खाली?)
  • नकारात्मक: सब कुछ स्ट्रिंग्स के रूप में संग्रहीत किया जाना है (यानी। nvarchar)
  • ऋणात्मक: कोड में सेटिंग्स के साथ काम करते समय, आपको यह जानना होगा कि सेटिंग किस प्रकार की है और इसे कास्ट करें

एकल पंक्ति विकल्प अब तक का सबसे आसान काम है। ऐसा इसलिए है क्योंकि आप डेटाबेस में प्रत्येक सेटिंग को अपने सही प्रकार में संग्रहीत कर सकते हैं और कोड में उनकी लुकिंग कुंजियों के साथ-साथ सेटिंग्स के प्रकारों को संग्रहीत करने की आवश्यकता नहीं है।

एक चीज जो मैं इस दृष्टिकोण के उपयोग से संबंधित था, वह "विशेष" एकल पंक्ति सेटिंग्स तालिका में कई पंक्तियाँ थी। मैं इसे (SQL सर्वर में) से आगे निकलता हूं:

  • 0 के डिफ़ॉल्ट मान के साथ एक नया बिट कॉलम जोड़ना
  • यह सुनिश्चित करने के लिए कि इस कॉलम में 0 का मान है, एक चेक बाधा बना रहा है
  • बिट कॉलम पर एक अद्वितीय बाधा पैदा करना

इसका मतलब यह है कि तालिका में केवल एक पंक्ति मौजूद हो सकती है क्योंकि बिट कॉलम में 0 का मान होना चाहिए, लेकिन अद्वितीय अवरोध के कारण उस मान के साथ केवल एक पंक्ति हो सकती है।


5
हम अपने LOB एप्लिकेशन में एकल-पंक्ति कार्य करते हैं। मान सभी सही प्रकार के होते हैं, जो अनुप्रयोग में उनका उपयोग बहुत सरल करता है। हमारे स्कीमा को एप्लिकेशन के साथ-साथ संस्करणित किया जाता है, इसलिए कॉन्फ़िगरेशन सेटअप में परिवर्तन किसी भी एप्लिकेशन संशोधन की तरह प्रबंधित किया जाता है।
डेव

17
एकल पंक्ति धनात्मक: FK को कुछ स्तंभों पर परिभाषित किया जा सकता है!
wqw

8
आप हमेशा यह निर्धारित करने के लिए एक प्रकार के पहचानकर्ता के साथ एक कुंजी / मान युग्म कर सकते हैं कि किस स्तंभ का मान उसके प्रकार में है। यह आपको दोनों दुनियाओं में सबसे अच्छा देता है और जब आपको इसकी आवश्यकता होती है तो आप मूल्य प्राप्त करने के लिए एक संग्रहीत खरीद का उपयोग कर सकते हैं।
Middletone

19
एकल-पंक्ति समाधान को लागू करने के बाद एक दिन जो वास्तव में आपके दिन को बर्बाद कर सकता है, वह यह है कि जब आपको बाद में "चलो आखिरी समय का भी ध्यान रखें तो प्रत्येक मूल्य को बदल दिया गया था और जिसने इसे बदल दिया ...."
डेव मेटेर

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

10

आपको सूचना प्रकार और सूचना मूल्य (कम से कम) के लिए एक स्तंभ के साथ एक तालिका बनानी चाहिए। इस तरह आप हर बार एक नई जानकारी जोड़ने के लिए नए कॉलम बनाने से बचते हैं।


1
सरल और साफ। बस वहाँ से प्रमुख मूल्य जोड़े की एक सूची के साथ काम करें। आप डिफ़ॉल्ट मानों के बारे में थोड़ा सोचना चाहते हैं, उपयोग के संदर्भ पर निर्भर करता है ...
पॉल कोहलर

4
नए कॉलम बनाने में समस्या क्यों है? मुझे पता है कि ऐसे हालात हैं जहां डेवलपर्स को एसक्यूएल स्कीमा को अपडेट करने के साथ राजनीतिक मुद्दों के कारण इससे बचना चाहिए, लेकिन प्रश्न में इसका कोई उल्लेख नहीं है।
फिन

6

एक पंक्ति ठीक काम करेगी; यह भी मजबूत प्रकार होगा:

show_borders    bit
admin_name      varchar(50)
max_users       int

एक नुकसान यह है कि alter tableनई सेटिंग जोड़ने के लिए स्कीमा परिवर्तन ( ) की आवश्यकता होती है । एक विकल्प सामान्य हो रहा है, जहां आप एक तालिका के साथ समाप्त होते हैं:

pref_name       varchar(50) primary key
pref_value      varchar(50) 

इसके कमजोर प्रकार हैं (सब कुछ एक वर्चर है), लेकिन एक नई सेटिंग को जोड़ना सिर्फ एक पंक्ति को जोड़ना है, कुछ ऐसा जो आप बस डेटाबेस लेखन एक्सेस के साथ कर सकते हैं।


4

व्यक्तिगत रूप से, मैं इसे एक ही पंक्ति में संग्रहीत करूंगा यदि यह काम करता है। SQL तालिका में संग्रहीत करने के लिए ओवरकिल? शायद, लेकिन ऐसा करने में कोई वास्तविक नुकसान नहीं है।


4

जैसा कि आपने अनुमान लगाया था, और सरलतम स्थितियों को छोड़कर, सभी कॉन्फ़िगरेशन मापदंडों को एक ही पंक्तियों में रखना कई कमियां हैं। यह एक बुरा विचार है ...

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

यदि आप रिलेशनल मॉडल के करीब रहना चाहते हैं , तो एंटिटी-एट्रीब्यूट-वैल्यू मॉडल शायद वही हो, जिसकी आपको आवश्यकता है, जिसके तहत व्यक्तिगत मानों को एक तालिका में संग्रहीत किया जाता है जो आमतौर पर ऐसा दिखता है:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

जिससे AttributeId एक तालिका के लिए एक विदेशी कुंजी है जहाँ प्रत्येक संभावित गुण (आपके मामले में "कॉन्फ़िगरेशन पैरामीटर") को कहा जाता है,

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

अंत में EntityId आपको कुछ इकाई की पहचान करने की अनुमति देता है जो इन विभिन्न विशेषताओं का "मालिक" है। आपके मामले में यह एक UserId या यहाँ तक कि निहित हो सकता है यदि आपके पास प्रबंधन करने के लिए केवल एक कॉन्फ़िगरेशन है।

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


3
यह कॉन्फ़िगरेशन तालिका के अधिकांश उपयोगों के लिए ओवरकिल जैसा लगता है।
जैरोल

मुझे लगता है कि इस दृष्टिकोण के पीछे सामान्य विचार महान है। लेकिन XML क्यों? केवल JSON या YAML की तरह एक साधारण डेटा इंटरचेंज प्रारूप चुनें और आप दोनों अन्य विविधताओं से लाभ उठा सकते हैं।
श्लोमर

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

3

सामान्यीकृत दृष्टिकोण में एक नया कॉन्फ़िगरेशन पैरामीटर जोड़ते समय आपको निश्चित रूप से अपना स्कीमा बदलना नहीं पड़ता है, लेकिन नए मूल्य को संसाधित करने के लिए आप शायद अपना कोड बदल रहे हैं।

अपनी तैनाती के लिए "परिवर्तन तालिका" जोड़ना ऐसा प्रतीत नहीं होता है कि एकल पंक्ति दृष्टिकोण की सादगी और प्रकार की सुरक्षा के लिए एक बड़ा व्यापार है।


2

एक कुंजी और मूल्य जोड़ी एक .Net App.Config के समान है जो कॉन्फ़िगरेशन सेटिंग्स को संग्रहीत कर सकता है।

इसलिए जब आप उस मूल्य को पुनः प्राप्त करना चाहते हैं जो आप कर सकते थे:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';

1

ऐसा करने का एक सामान्य तरीका एक गुण फ़ाइल में "गुण" तालिका सिमुलर है। यहां आप अपने सभी ऐप स्थिरांक को स्टोर कर सकते हैं, या इतनी निरंतर चीजें नहीं हैं, जिन्हें आपको बस पास होना चाहिए।

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

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

इस तरह आप अपने पास मौजूद डेटा और अगले साल होने वाले डेटा को स्टोर कर सकते हैं और अभी तक इसके बारे में नहीं जानते हैं :)।

इस उदाहरण में, आपके दायरे और refId का उपयोग बैक एंड पर जो कुछ भी आप चाहते हैं, के लिए किया जा सकता है। इसलिए अगर प्रॉपर्टी टाइप "ADMIN" का दायरा 0 refId 2 है, तो आप जानते हैं कि यह क्या प्राथमिकता है।

संपत्ति का प्रकार हाथ में आता है जब, किसी दिन, आपको गैर-व्यवस्थापक जानकारी को यहां भी संग्रहीत करने की आवश्यकता है।

ध्यान दें कि आपको कार्ट डेटा को इस तरह से संग्रहीत नहीं करना चाहिए, या उस मामले के लिए लुकअप नहीं करना चाहिए। हालांकि यदि डेटा सिस्टम विशिष्ट है, तो आप निश्चित रूप से इस पद्धति का उपयोग कर सकते हैं।

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

मुद्दा यह है कि आप कार्ट से संबंधित चीजों के लिए इसका उपयोग नहीं करना चाहते हैं। आप व्यापार तर्क को अच्छी तरह से परिभाषित संबंधपरक तालिकाओं में रखें। गुण तालिका केवल सिस्टम जानकारी के लिए है।


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

नोट: उन्होंने कहा कि "सेटिंग्स और कॉन्फ़िगरेशन को बचाएं", "मुझे रिलेशनल कार्ट डेटा को बचाने की आवश्यकता नहीं है"
स्टेफ़ानो

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

मेरी पहली वृत्ति केवल इस डेटा को एक फ्लैट फ़ाइल में जोड़ना है। और आप सही हैं, इसके बजाय तालिका का उपयोग करने की यह प्रक्रिया वास्तव में डीबीएमएस के बाधा तंत्र को दरकिनार करेगी। हालाँकि, मैं कहूंगा कि यदि आप उचित डेटाबेस तकनीकों का पालन करने की बहुत कोशिश करते हैं, तो आप इस बिंदु को याद नहीं कर रहे हैं। पहले उत्तर की जाँच करें; SO पर सबसे अधिक मतदान किया गया: stackoverflow.com/questions/406760/…
स्टेफानो

2
मैं मुख्य मूल्य जोड़ी पर जाऊंगा, इसे स्टार्टअप पर एक शब्दकोष और आपके सॉर्ट किए गए तरीके से हटा दूंगा।
बजे पॉल क्रीज

0

मुझे यकीन नहीं है कि कॉन्फ़िगरेशन के लिए एक एकल पंक्ति सबसे अच्छा कार्यान्वयन है। आप दो कॉलम (configName, configValue) के साथ प्रति कॉन्फ़िगरेशन आइटम की एक पंक्ति होने से बेहतर हो सकते हैं, हालांकि इसके लिए आपके सभी मानों को तार और पीछे की आवश्यकता होगी।

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


0

आप प्रत्येक प्रमुख प्रकार के लिए एक कॉलम जोड़कर और बिना यह बताए कि डेटा किस कॉलम में है, आप बिना कुंजी / मान जोड़ी के रूपांतरण कर सकते हैं।

तो आपकी तालिका कुछ इस तरह दिखाई देगी:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

यह थोड़ा अधिक कमरे का उपयोग करता है लेकिन अधिकांश में आप कुछ दर्जन विशेषताओं का उपयोग कर रहे हैं। सही फ़ील्ड को खींचने / शामिल करने के लिए आप कॉलम_num मान से केस स्टेटमेंट का उपयोग कर सकते हैं।


0

सॉरी मैं आती हूं, यारों बाद में। लेकिन वैसे भी, मैं जो भी करता हूं वह सरल और प्रभावी है। मैं केवल तीन () कॉलम के साथ एक तालिका बनाता हूं:

आईडी - int (11)

नाम - वर्चर (64)

मूल्य - पाठ

एक नया कॉन्फिगरेशन कॉलम बनाने से पहले मैं क्या करता हूं, इसे अपडेट करना या पढ़ना "मूल्य" को क्रमबद्ध करना है! इस तरह से मुझे यकीन है कि टाइप (खैर, php :) है)

उदाहरण के लिए:

ख: 0; के लिए है बी OOLEAN ( झूठी )

ख: 1; के लिए है बी (OOLEAN सच )

मैं: 1988; के लिए है मैं NT

s: 5: "कादेर"; 5 वर्णों की लंबाई के S TRING के लिए है

आशा है कि ये आपकी मदद करेगा :)


1
केवल प्रकार के लिए एक नया कॉलम क्यों नहीं बनाएं? i:1988ऐसा लगता है कि आप जानकारी के दो टुकड़ों को एक कॉलम में समेटने का प्रयास कर रहे हैं।
maksymiuk

@maksymiuk SImply क्योंकि एक बार अनजाने में आपको (यदि या स्विच) के बाद लूप का उपयोग करने के बजाय सटीक प्रकार मिलता है ... आदि
Kader Bouyakoub

किसी भी छोरों या स्विच या किसी भी चीज की आवश्यकता नहीं है, यह वास्तव में प्रत्येक पंक्ति से जानकारी को पार्स करने के चरण को हटा देगा, जबकि, यदि आपके पास प्रकार के लिए एक अतिरिक्त कॉलम था, तो जानकारी को खींचने वाले घटक के लिए टाइप जानकारी पहले से ही उपलब्ध है केवल प्रारंभिक क्वेरी की तुलना में आगे कोई कदम उठाए बिना
maksymiuk

echo (int) $varएक पूर्णांक और अन्य प्रकार के लिए दूसरों की तरह कुछ करने से आपका मतलब है ?
कादर बौआकोब

0

वार्निश के रूप में एक प्रमुख स्तंभ और JSON के रूप में एक मान स्तंभ है। 1संख्यात्मक है जबकि "1"एक स्ट्रिंग है। trueऔर falseदोनों बूलियन हैं। आपके पास वस्तुएं भी हो सकती हैं।

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