सॉर्ट की गई सूची को संग्रहीत करने के लिए डेटाबेस कैसे डिज़ाइन करें?


42

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

  1. डालें (x) - तालिका में रिकॉर्ड x डालें
  2. Delete (x) - टेबल से record x हटाएं
  3. पहले (x, n) - सॉर्ट की गई सूची में रिकॉर्ड x से पहले के 'n' रिकॉर्ड लौटाएं।
  4. बाद में (x, n) - सॉर्ट की गई सूची में रिकॉर्ड x को सफल करते हुए 'n' रिकॉर्ड लौटाएं।
  5. पहला (n) - पहले छांटे गए सूची से 'एन' रिकॉर्ड लौटाएं।
  6. अंतिम (n) - क्रमबद्ध सूची से अंतिम 'एन' रिकॉर्ड लौटाएं।
  7. तुलना करें (x, y) - तालिका से दो रिकॉर्ड x और y को देखते हुए, पता लगाएँ कि क्या x> y है।

जिस सरल विधि के बारे में मैं सोच सकता था, वह है उस विशेषता को छाँट कर तालिका और क्वेरी में किसी प्रकार की 'रैंक' विशेषता को संग्रहित करना। लेकिन इस विधि में एक रैंक के साथ रिकॉर्ड सम्मिलित / संशोधित करना एक महंगा ऑपरेशन बन जाता है। क्या कोई बेहतर तरीका है?

विशेष रूप से, मैं Amazon के SimpleDB का उपयोग करके तालिका को लागू करना चाह रहा हूं। लेकिन रिलेशनल डेटाबेस के लिए एक सामान्य उत्तर भी सहायक होना चाहिए।

लोड प्रोफ़ाइल पर अपडेट करें:

चूंकि मैं एक वेब एप्लिकेशन के लिए यह योजना बना रहा हूं, यह ऐप का उपयोग करने वाले उपयोगकर्ताओं की संख्या पर निर्भर करता है।

यदि 100k सक्रिय उपयोगकर्ता (सुपर आशावाद: पी) हैं, तो प्रति दिन मेरा बहुत अनुमानित अनुमान होगा

500k चयन, 100k आवेषण और हटाता है, 500k अद्यतन करता है

मुझे उम्मीद है कि तालिका कुल 500k तक बढ़ेगी।

मैं अपडेट, इंसर्ट और तुलना ऑपरेशन पर ऑप्टिमाइज़ करना चाह रहा हूँ। वस्तुओं की रैंक लगातार बदल रही होगी और मुझे तालिका को अद्यतन रखने की आवश्यकता है।


अपने अपेक्षित लोड प्रोफ़ाइल पर थोड़ा विस्तार करें। प्रति दिन कितने चयन / आवेषण / अद्यतन? ऑप्टिमाइज़ेशन के लिए आप कौन से ऑपरेशन चाहते हैं? आप प्रति दिन बढ़ने या कुल प्राप्त करने की मेज की कितनी उम्मीद करते हैं?
निक चामास

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

नहीं, यह खिलाड़ी रैंकिंग बोर्ड नहीं है।
चिट्टी

आपने किस दृष्टिकोण का उपयोग किया है?
निक चामास

मुझे यहां तक ​​निश्चित नहीं है कि यहां क्या पूछा जा रहा है या आपको उन चीजों की लॉन्ड्री सूची से क्या करने की जरूरत नहीं है जो आपको करने की आवश्यकता है।
इवान कैरोल

जवाबों:


22

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

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

यह देखते हुए कि आप उच्च प्रविष्टि और अद्यतन गतिविधि की अपेक्षा करते हैं, लेकिन यह भी अपेक्षाकृत उच्च गतिविधि पढ़ें, मैं निम्नलिखित करने की सलाह देता हूं:

  • रैंक पर तालिका को क्लस्टर करें, खासकर यदि आपके प्रश्नों का विशाल बहुमत रैंक के खिलाफ है। यदि नहीं, या यदि एक क्लस्टरिंग कुंजी को चुनना सिम्प्लीडीबी में उपलब्ध नहीं है, तो बस अग्रणी कॉलम के रूप में रैंक के साथ एक इंडेक्स बनाएं। यह 3-6 प्रश्नों को संतुष्ट करेगा।
  • पहले रिकॉर्ड और फिर रैंक (या, SQL सर्वर की दुनिया में, सिर्फ रिकॉर्ड और INCLUDEरैंक रैंक, या सिर्फ रिकॉर्ड अगर आपने रैंक पर क्लस्टर किया है) पर एक इंडेक्स क्वेरी 7 को संतुष्ट करेगा।
  • संचालन 1 और 2 को आपके डेटा को उचित रूप से अलग करके ( FILLFACTORSQL सर्वर में सेट करके ) अनुकूलित किया जा सकता है । यह विशेष रूप से महत्वपूर्ण है यदि आप रैंक पर क्लस्टर करते हैं।
  • जब आप रैंक डालते या अपडेट करते हैं, तो रैंक संख्याओं के बीच अधिक से अधिक अंतर बनाए रखें ताकि इस संभावना को कम किया जा सके कि आपको रैंक डालने या अपडेट करने के लिए मौजूदा रिकॉर्ड को फिर से रैंक करना होगा। उदाहरण के लिए, यदि आप 1000 के चरणों में अपने रिकॉर्ड को रैंक करते हैं, तो आप लगभग आधे के लिए पर्याप्त जगह छोड़ देते हैं कि कई बदलाव और न्यूनतम अवसर के साथ आवेषण आपको उन परिवर्तनों में सीधे शामिल नहीं होने वाले रिकॉर्ड को फिर से रैंक करने की आवश्यकता होगी।
  • हर रात उनके बीच रैंक अंतराल को रीसेट करने के लिए सभी रिकॉर्ड को फिर से रैंक करते हैं।
  • आप मास रि-रैंकिंग की आवृत्ति के साथ-साथ मौजूदा रिकॉर्ड की संख्या के सापेक्ष आवेषण या अपडेट की संख्या को समायोजित करने के लिए रैंक गैप साइज को भी ट्यून कर सकते हैं। इसलिए यदि आपके पास 100K रिकॉर्ड है और आपके आवेषण और अपडेट 10% होने की उम्मीद करते हैं, तो 10K नए रैंक के लिए पर्याप्त जगह छोड़ दें और रात को फिर से रैंक करें।
  • 500K रिकॉर्ड को फिर से रैंकिंग करना एक महंगा ऑपरेशन है, लेकिन दिन में एक बार या सप्ताह में एक बार किया जाना इस तरह डेटाबेस के लिए ठीक होना चाहिए। रैंक अंतराल को बनाए रखने के लिए यह ऑफ-मास मास री-रैंकिंग है जो आपको प्रत्येक रैंक अपडेट के लिए कई रिकॉर्ड्स को फिर से रैंक करने या आपके सामान्य और पीक घंटों के दौरान सम्मिलित करने से बचाता है।

यदि आप 100K + 100K + आकार की मेज पर पढ़ते हैं, तो मैं लिंक किए गए सूची दृष्टिकोण का उपयोग करने की अनुशंसा नहीं करता हूं। यह उन आकारों में अच्छी तरह से पैमाना नहीं होगा।


रैंकों को संशोधित किया जा सकता है। मैं उम्मीद कर रहा हूं कि रैंकों में लगातार बदलाव होंगे और नए रिकॉर्ड लगातार डाले जा रहे हैं। मैं उस मामले को लेकर चिंतित हूं, जब मैं एक रैंक के साथ एक नया तत्व सम्मिलित करता हूं तब क्रमबद्ध रूप से नए रिकॉर्ड के नीचे सभी रिकॉर्ड की रैंक को बदलने की आवश्यकता होती है। क्या यह महंगा ऑपरेशन नहीं है जब मेरे डेटाबेस में हजारों रिकॉर्ड हैं?
चिट्टी

@ चिट्टी - आह, यह एक चिंता का विषय है। आप अपनी रैंकिंग (जैसे 0, 1000, 2000, 3000, ...) को अंतरिक्ष में रख सकते हैं और समय-समय पर सभी रिकॉर्ड्स को फिर से रैंक कर सकते हैं, क्योंकि रैंक में सुधार होता है। यदि आप हजारों रिकॉर्ड के कुछ दसियों से अधिक की अपेक्षा करते हैं, तो यह पैमाना नहीं होगा।
निक चामास

1
@chitti - यह थोड़े मजाकिया है, वास्तव में। यह वास्तव में समस्या डेटाबेस इंजन डेटा को अनुक्रमित करते समय सौदा करते हैं, क्योंकि वे इसे आदेश दे रहे हैं और डेटा को जोड़ने या बदलने के रूप में इसे फिर से आदेश दे रहे हैं। यदि आप FILLFACTORदेखते हैं तो आप देखेंगे कि यह मूल रूप से एक इंडेक्स में रिकॉर्ड के लिए अतिरिक्त स्थान बनाने के लिए है, जैसे कि रैंक अंतराल मैंने वर्णित किया है कि रैंक में बदलाव और सम्मिलन के लिए जगह बनाते हैं।
निक चम्मास

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

@ चिट्टी - उस SO प्रश्न का स्वीकृत उत्तर बहुत अच्छा है। यह वही दृष्टिकोण बताता है जो मैंने यहां विस्तृत किया है, पूर्णांक के बजाय दशमलव का उपयोग करने के अतिरिक्त सुझाव के साथ रैंक को असाइन करने और बदलने में आपके लचीलेपन का विस्तार करने के लिए। शानदार खोज।
निक चामास

13

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

एक वैकल्पिक दृष्टिकोण तालिका में "पूर्ववर्ती" रिफ्लेक्सिव विदेशी कुंजी कॉलम का उपयोग करके रिकॉर्ड को एक लिंक्ड सूची के रूप में मॉडल करना होगा:

ID   setID   item       predecessor
---  ------  ------     ------------
1    1       Apple      null
2    1       Orange     1
3    2       Cucumber   null
4    1       Pear       2
5    1       Grape      4
6    2       Carrot     3

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

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


2
जुड़ा हुआ सूची मॉडल साफ-सुथरा है। SQL सर्वर में इस तरह के पदानुक्रम को पुनः प्राप्त करने के लिए आप पुनरावर्ती CTE का उपयोग करेंगे ।
निक चामास

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

लिंक किए गए सूची विकल्प तुलना के अलावा सभी कार्यों के लिए सबसे अच्छा विचार है। किसी भी विचार मैं दो तत्वों के बीच पथ का पता लगाने के बिना तुलना कैसे लागू करेंगे?
चित्ती

यदि आपके पास मेरे द्वारा तुलना किए जाने वाले आइटमों की आईडी है (तो) सीधा होगा, जब तक कि मुझे गलतफहमी न हो कि आपकी तुलना का क्या मतलब है ()। जब आपने कहा: "यह पता करें कि क्या x> y" का मतलब "x पूर्व y है?" मैं यह नहीं देख सकता कि कस्टम सूचकांक या संग्रहित प्रक्रिया के बिना आसान होना जो सूची को चलाएगा (या @Nick द्वारा उल्लिखित दिलचस्प सीटीई सुविधा)।
बोनापुल्ला

5
इस प्रकार का समाधान एक ग्राफ डेटा मॉडल ( en.wikipedia.org/wiki/Graph_theory ) का भी अनुमान लगाता है । भंडारण नोड्स और किनारों के भंडारण के लिए अनुकूलित एक स्टोरेज सिस्टम RDBMS से बेहतर समाधान हो सकता है। ट्रिपल- और क्वाड-स्टोर और Neo4J जैसे ग्राफ डेटाबेस इस पर बहुत अच्छे हैं।
बोनापुल्ला

6

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


2
क्या होगा अगर 'गुण जो रैंक की गणना करने के लिए उपयोग किए जाते हैं' मनमाने हैं? उदा: शॉपिंग कार्ट प्रविष्टियों का एक सेट जो उपयोगकर्ता की मनमानी क्रियाओं के आधार पर पुनः व्यवस्थित हो जाता है।
चिट्टी

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

मान लीजिए कि हमें खरीदारी की टोकरी में वस्तुओं के क्रम को बनाए रखने की आवश्यकता है और उपयोगकर्ता द्वारा वेब यूई का उपयोग करके आदेश को 'मनमाने ढंग से' बदला जा सकता है। आप डेटाबेस में आइटमों की ऐसी सूची को कैसे संग्रहीत करेंगे और आप क्रमबद्धता कैसे बनाए रखेंगे?
चिट्टी

यदि मैं आपको सही ढंग से समझता हूं, तो खरीदारी की गाड़ी में आइटम के क्रम को "मनमाने ढंग से बदलकर" से आपका मतलब है कि उपयोगकर्ता किसी सूची में आइटम को ऊपर और नीचे खींच सकते हैं और उन्हें जहां चाहें वहां गिरा सकते हैं। मुझे लगता है कि मुझे एक छोटे से वंचित के रूप में हमला करता है। उपयोगकर्ता ऐसा क्यों करेंगे? अगर वे ऐसा कर पाते, तो क्या वे इसे बहुत कुछ करते? क्या एक कार्ट के भीतर वस्तुओं का एक सरल अनुक्रम वास्तव में प्रदर्शन की बहुत चिंता है? यह मुझे लगता है कि कार्ट में आइटमों की संख्या के लिए एक क्रम संख्या + एफके से ऑर्डर आपको आपको आवश्यक सूचकांक दे देगा। जब कोई सामान इधर-उधर हो जाए तो बस अपडेट करें।
जोएल ब्राउन

3
खरीदारी की टोकरी सिर्फ एक उदाहरण है जो मैंने यह दिखाने के लिए दिया था कि ऐसे मामले हैं जहां 'रैंक' मनमानी हो सकती है। हो सकता है कि यह एक महान उदाहरण नहीं था। नेटफ्लिक्स डीवीडी कतार एक बेहतर उदाहरण हो सकता है। बस तर्क के लिए 100k आइटम के साथ एक नेटफ्लिक्स कतार की कल्पना करें जिसे उपयोगकर्ता द्वारा मनमाने ढंग से फिर से चलाया जा सकता है और वह हर एक मिनट में ऐसा करता है। आप इस काल्पनिक अनुप्रयोग में फिल्मों की सूची बनाने के लिए एक डेटाबेस कैसे डिज़ाइन करेंगे?
चिट्टी

1

ये साधारण आरडीबी जैसे गैर-आरडीबीएमएस की सीमाएं हैं। आपको जिन सुविधाओं की आवश्यकता होती है, उन्हें साधारण डीडीबी में लागू नहीं किया जा सकता है, उन्हें प्रोग्रामिंग साइड / एप्लिकेशन से कार्यान्वित किया जाना चाहिए।

RDBMS की तरह SQL server, आपके लिए आवश्यक सुविधाएँ क्लस्टर इंडेक्स के लिए अल्पविकसित हैं।

  • सम्मिलित करें (x) - तालिका में रिकॉर्ड x डालें> सरल डालें।
  • Delete (x) - टेबल से record x हटाएं> Simple Delete करें।
  • पहले (x, n) - सॉर्ट की गई सूची में रिकॉर्ड x से पहले के 'n' रिकॉर्ड लौटाएं। > शीर्ष n परिणामों का चयन करें, जहां खंड द्वारा x मूल्य और क्रम से कम है।

  • बाद में (x, n) - सॉर्ट की गई सूची में रिकॉर्ड x को सफल करते हुए 'n' रिकॉर्ड लौटाएं। > शीर्ष n परिणामों का चयन करें जहां खंड से x अधिक मूल्य और क्रम है।

  • पहला (n) - पहले छांटे गए सूची से 'एन' रिकॉर्ड लौटाएं। > शीर्ष n परिणाम चुनें।

  • अंतिम (n) - क्रमबद्ध सूची से अंतिम 'एन' रिकॉर्ड लौटाएं। > Desc द्वारा आदेश के बाद शीर्ष n परिणाम का चयन करें।

  • तुलना करें (x, y) - तालिका से दो रिकॉर्ड x और y को देखते हुए, पता लगाएँ कि क्या x> y है। > TSQL अगर बयान।

SimpleDB स्वचालित अनुक्रमित, छँटाई और एक बुनियादी क्वेरी भाषा प्रदान करता है । अगर मैं RDBMS चुनता हूं तो भी मेरी समस्या बनी रहेगी। समस्या यह है क्योंकि मेरे डेटाबेस में डेटा की रैंकिंग मनमाने ढंग से बदल जाती है और उन्हें एक ही संपत्ति (जब तक कि मैं एक कस्टम रैंक कॉलम का उपयोग नहीं करता) को अनुक्रमित किया जा सकता है।
चिट्टी

0

यहाँ मैं हर पोस्ट के बाद अपनी पोस्टग्रैज टेबल को फिर से रैंक करता था:

CREATE OR REPLACE FUNCTION re_rank_list() RETURNS trigger AS $re_rank_list$
DECLARE
    temprow record;
    row_idx integer := 1;    
BEGIN
    FOR temprow IN
    SELECT * FROM your_schema.your_list WHERE list_id = NEW.list_id ORDER BY rank ASC
    LOOP
        UPDATE your_schema.your_list SET rank = row_idx * 100 WHERE id = temprow.id;
        row_idx := row_idx + 1;
    END LOOP;
    RETURN NEW;
END;
$re_rank_list$ LANGUAGE plpgsql;


CREATE TRIGGER re_rank_list AFTER UPDATE ON your_schema.your_list_value
    FOR EACH ROW 
    WHEN (pg_trigger_depth() = 0)
    EXECUTE PROCEDURE re_rank_list();

मेरे उपयोग-मामले के लिए, प्रदर्शन एक चिंता का विषय नहीं है, लेकिन विश्वास है कि यह कभी नहीं टूटेगा या अजीब तरह से कार्य करेगा महत्वपूर्ण है।

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