इंडेक्स सभी डेटाबेस के लिए उचित डेटा मॉडलिंग का एक महत्वपूर्ण हिस्सा हैं, और डायनेमोडीबी कोई अपवाद नहीं है। डायनेमोडीबी के सेकेंडरी इंडेक्स आपके डेटा के लिए नए एक्सेस पैटर्न को सक्षम करने के लिए एक शक्तिशाली उपकरण हैं।
इस पोस्ट में, हम DynamoDB सेकेंडरी इंडेक्स पर नज़र डालेंगे। सबसे पहले, हम DynamoDB के बारे में सोचने के तरीके और सेकेंडरी इंडेक्स द्वारा हल की जाने वाली समस्याओं के बारे में कुछ वैचारिक बिंदुओं से शुरुआत करेंगे। फिर, हम सेकेंडरी इंडेक्स को प्रभावी ढंग से इस्तेमाल करने के लिए कुछ व्यावहारिक सुझावों पर नज़र डालेंगे। अंत में, हम कुछ विचारों के साथ समाप्त करेंगे कि आपको सेकेंडरी इंडेक्स का उपयोग कब करना चाहिए और आपको कब अन्य समाधानों की तलाश करनी चाहिए।
आएँ शुरू करें।
इससे पहले कि हम सेकेंडरी इंडेक्स के उपयोग के मामलों और सर्वोत्तम प्रथाओं पर चर्चा करें, हमें पहले यह समझना चाहिए कि डायनेमोडीबी सेकेंडरी इंडेक्स क्या हैं। और ऐसा करने के लिए, हमें यह समझना चाहिए कि डायनेमोडीबी कैसे काम करता है।
यह DynamoDB की कुछ बुनियादी समझ को मानता है। हम उन बुनियादी बिंदुओं को कवर करेंगे जिन्हें आपको सेकेंडरी इंडेक्स को समझने के लिए जानना आवश्यक है, लेकिन यदि आप DynamoDB के लिए नए हैं, तो आप अधिक बुनियादी परिचय के साथ शुरू करना चाह सकते हैं।
डायनेमोडीबी एक अनूठा डेटाबेस है। इसे OLTP वर्कलोड के लिए डिज़ाइन किया गया है, जिसका अर्थ है कि यह बहुत सारे छोटे ऑपरेशन को संभालने के लिए बढ़िया है - शॉपिंग कार्ट में कोई आइटम जोड़ना, वीडियो को लाइक करना या Reddit पर कोई टिप्पणी जोड़ना जैसी चीज़ों के बारे में सोचें। इस तरह, यह आपके द्वारा उपयोग किए गए अन्य डेटाबेस जैसे MySQL, PostgreSQL, MongoDB या Cassandra जैसे समान अनुप्रयोगों को संभाल सकता है।
डायनेमोडीबी का मुख्य वादा किसी भी पैमाने पर लगातार प्रदर्शन की गारंटी है। चाहे आपकी तालिका में 1 मेगाबाइट डेटा हो या 1 पेटाबाइट डेटा, डायनेमोडीबी आपके ओएलटीपी-जैसे अनुरोधों के लिए समान विलंबता रखना चाहता है। यह एक बड़ी बात है - जब आप डेटा की मात्रा या समवर्ती अनुरोधों की संख्या बढ़ाते हैं तो कई डेटाबेस कम प्रदर्शन देखेंगे। हालाँकि, ये गारंटी प्रदान करने के लिए कुछ समझौतों की आवश्यकता होती है, और डायनेमोडीबी में कुछ अनूठी विशेषताएँ हैं जिन्हें आपको इसे प्रभावी ढंग से उपयोग करने के लिए समझने की आवश्यकता है।
सबसे पहले, DynamoDB आपके डेटा को हुड के नीचे कई विभाजनों में फैलाकर आपके डेटाबेस को क्षैतिज रूप से स्केल करता है। ये विभाजन आपको एक उपयोगकर्ता के रूप में दिखाई नहीं देते हैं, लेकिन वे DynamoDB के काम करने के तरीके के मूल में हैं। आप अपनी तालिका के लिए एक प्राथमिक कुंजी निर्दिष्ट करेंगे (या तो एक एकल तत्व, जिसे 'विभाजन कुंजी' कहा जाता है, या विभाजन कुंजी और सॉर्ट कुंजी का संयोजन), और DynamoDB उस प्राथमिक कुंजी का उपयोग यह निर्धारित करने के लिए करेगा कि आपका डेटा किस विभाजन पर रहता है। आपके द्वारा किया गया कोई भी अनुरोध एक अनुरोध राउटर के माध्यम से जाएगा जो यह निर्धारित करेगा कि किस विभाजन को अनुरोध को संभालना चाहिए। ये विभाजन छोटे होते हैं - आम तौर पर 10GB या उससे कम - इसलिए उन्हें स्थानांतरित, विभाजित, प्रतिकृति और अन्यथा स्वतंत्र रूप से प्रबंधित किया जा सकता है।
शार्डिंग के माध्यम से क्षैतिज स्केलेबिलिटी दिलचस्प है, लेकिन यह किसी भी तरह से डायनेमोडीबी के लिए अद्वितीय नहीं है। कई अन्य डेटाबेस - रिलेशनल और नॉन-रिलेशनल दोनों - क्षैतिज रूप से स्केल करने के लिए शार्डिंग का उपयोग करते हैं। हालाँकि, डायनेमोडीबी के लिए जो अद्वितीय है वह यह है कि यह आपको अपने डेटा तक पहुँचने के लिए अपनी प्राथमिक कुंजी का उपयोग करने के लिए मजबूर करता है। क्वेरी प्लानर का उपयोग करने के बजाय जो आपके अनुरोधों को क्वेरी की एक श्रृंखला में अनुवाद करता है, डायनेमोडीबी आपको अपने डेटा तक पहुँचने के लिए अपनी प्राथमिक कुंजी का उपयोग करने के लिए मजबूर करता है । आप अनिवार्य रूप से अपने डेटा के लिए एक सीधे पता योग्य इंडेक्स प्राप्त कर रहे हैं।
DynamoDB के लिए API इसे दर्शाता है। अलग-अलग आइटम ( GetItem
, PutItem
, UpdateItem
, DeleteItem
) पर कई ऑपरेशन हैं जो आपको अलग-अलग आइटम पढ़ने, लिखने और हटाने की अनुमति देते हैं। इसके अतिरिक्त, एक Query
ऑपरेशन है जो आपको एक ही पार्टीशन कुंजी के साथ कई आइटम प्राप्त करने की अनुमति देता है। यदि आपके पास एक समग्र प्राथमिक कुंजी वाली तालिका है, तो समान पार्टीशन कुंजी वाले आइटम एक ही पार्टीशन पर एक साथ समूहीकृत किए जाएँगे। उन्हें सॉर्ट कुंजी के अनुसार क्रमबद्ध किया जाएगा, जिससे आप "किसी उपयोगकर्ता के लिए सबसे हाल के ऑर्डर प्राप्त करें" या "किसी IoT डिवाइस के लिए अंतिम 10 सेंसर रीडिंग प्राप्त करें" जैसे पैटर्न को संभाल सकेंगे।
उदाहरण के लिए, आइए एक SaaS एप्लिकेशन की कल्पना करें जिसमें उपयोगकर्ताओं की एक तालिका है। सभी उपयोगकर्ता एक ही संगठन से संबंधित हैं। हमारे पास एक तालिका हो सकती है जो इस प्रकार दिखती है:
हम 'संगठन' की विभाजन कुंजी और 'उपयोगकर्ता नाम' की सॉर्ट कुंजी के साथ एक समग्र प्राथमिक कुंजी का उपयोग कर रहे हैं। यह हमें किसी व्यक्तिगत उपयोगकर्ता को उनके संगठन और उपयोगकर्ता नाम प्रदान करके लाने या अपडेट करने के लिए ऑपरेशन करने की अनुमति देता है। हम Query
ऑपरेशन के लिए केवल संगठन प्रदान करके एक ही संगठन के सभी उपयोगकर्ताओं को भी ला सकते हैं।
कुछ बुनियादी बातों को ध्यान में रखते हुए, आइए अब सेकेंडरी इंडेक्स पर नज़र डालें। सेकेंडरी इंडेक्स की ज़रूरत को समझने का सबसे अच्छा तरीका यह समझना है कि वे किस समस्या का समाधान करते हैं। हमने देखा है कि डायनेमोडीबी आपके डेटा को आपकी प्राथमिक कुंजी के अनुसार कैसे विभाजित करता है और यह आपको अपने डेटा तक पहुँचने के लिए प्राथमिक कुंजी का उपयोग करने के लिए कैसे प्रेरित करता है। कुछ एक्सेस पैटर्न के लिए यह सब ठीक है, लेकिन क्या होगा यदि आपको अपने डेटा को किसी अलग तरीके से एक्सेस करने की आवश्यकता हो?
ऊपर दिए गए हमारे उदाहरण में, हमारे पास उपयोगकर्ताओं की एक तालिका थी जिसे हमने उनके संगठन और उपयोगकर्ता नाम के आधार पर एक्सेस किया था। हालाँकि, हमें किसी एक उपयोगकर्ता को उनके ईमेल पते के आधार पर भी प्राप्त करना पड़ सकता है। यह पैटर्न प्राथमिक कुंजी एक्सेस पैटर्न के साथ फिट नहीं बैठता है जिसे DynamoDB हमें आगे बढ़ाता है। चूँकि हमारी तालिका अलग-अलग विशेषताओं द्वारा विभाजित है, इसलिए हमारे डेटा को जिस तरह से हम चाहते हैं, उस तरह से एक्सेस करने का कोई स्पष्ट तरीका नहीं है। हम एक पूर्ण तालिका स्कैन कर सकते हैं, लेकिन यह धीमा और अक्षम है। हम अपने डेटा को एक अलग प्राथमिक कुंजी के साथ एक अलग तालिका में डुप्लिकेट कर सकते हैं, लेकिन इससे जटिलता बढ़ जाती है।
यहीं पर सेकेंडरी इंडेक्स काम आते हैं। सेकेंडरी इंडेक्स मूल रूप से आपके डेटा की एक पूरी तरह से प्रबंधित कॉपी होती है जिसमें एक अलग प्राइमरी की होती है। आप इंडेक्स के लिए प्राइमरी की घोषित करके अपनी टेबल पर सेकेंडरी इंडेक्स निर्दिष्ट करेंगे। जैसे ही आपकी टेबल में लिखा जाएगा, डायनेमोडीबी अपने आप ही डेटा को आपके सेकेंडरी इंडेक्स में दोहरा देगा।
नोट *: इस अनुभाग में सब कुछ वैश्विक द्वितीयक इंडेक्स पर लागू होता है। DynamoDB स्थानीय द्वितीयक इंडेक्स भी प्रदान करता है, जो थोड़े अलग हैं। लगभग सभी मामलों में, आपको एक वैश्विक द्वितीयक इंडेक्स चाहिए होगा। अंतरों के बारे में अधिक जानकारी के लिए, वैश्विक या स्थानीय द्वितीयक इंडेक्स चुनने पर यह लेख देखें।*
इस मामले में, हम अपनी तालिका में "ईमेल" की विभाजन कुंजी के साथ एक द्वितीयक सूचकांक जोड़ेंगे। द्वितीयक सूचकांक इस प्रकार दिखेगा:
ध्यान दें कि यह वही डेटा है, इसे बस एक अलग प्राथमिक कुंजी के साथ पुनर्गठित किया गया है। अब, हम किसी उपयोगकर्ता को उसके ईमेल पते से कुशलतापूर्वक खोज सकते हैं।
कुछ मायनों में, यह अन्य डेटाबेस में मौजूद इंडेक्स के समान ही है। दोनों ही एक डेटा संरचना प्रदान करते हैं जो किसी विशेष विशेषता पर लुकअप के लिए अनुकूलित होती है। लेकिन डायनेमोडीबी के सेकेंडरी इंडेक्स कुछ प्रमुख तरीकों से अलग हैं।
सबसे पहले, और सबसे महत्वपूर्ण बात यह है कि डायनेमोडीबी के इंडेक्स आपकी मुख्य तालिका की तुलना में पूरी तरह से अलग विभाजन पर रहते हैं। डायनेमोडीबी चाहता है कि हर लुकअप कुशल और पूर्वानुमानित हो, और यह रैखिक क्षैतिज स्केलिंग प्रदान करना चाहता है। ऐसा करने के लिए, इसे आपके डेटा को उन विशेषताओं द्वारा फिर से तैयार करना होगा जिनका उपयोग आप इसे क्वेरी करने के लिए करेंगे।
अन्य वितरित डेटाबेस में, वे आम तौर पर सेकेंडरी इंडेक्स के लिए आपके डेटा को रीशर्ड नहीं करते हैं। वे आम तौर पर शार्ड पर सभी डेटा के लिए सेकेंडरी इंडेक्स को बनाए रखेंगे। हालाँकि, यदि आपके इंडेक्स शार्ड कुंजी का उपयोग नहीं करते हैं, तो आप अपने डेटा को क्षैतिज रूप से स्केल करने के कुछ लाभों को खो रहे हैं क्योंकि शार्ड कुंजी के बिना क्वेरी को आपके द्वारा खोजे जा रहे डेटा को खोजने के लिए सभी शार्ड में स्कैटर-गैदर ऑपरेशन करने की आवश्यकता होगी।
डायनेमोडीबी के सेकेंडरी इंडेक्स अलग होने का दूसरा तरीका यह है कि वे (अक्सर) पूरे आइटम को सेकेंडरी इंडेक्स में कॉपी करते हैं। रिलेशनल डेटाबेस पर इंडेक्स के लिए, इंडेक्स में अक्सर इंडेक्स किए जा रहे आइटम की प्राइमरी की के लिए पॉइंटर होता है। इंडेक्स में एक प्रासंगिक रिकॉर्ड का पता लगाने के बाद, डेटाबेस को पूरा आइटम लाने की आवश्यकता होगी। क्योंकि डायनेमोडीबी के सेकेंडरी इंडेक्स मुख्य तालिका की तुलना में अलग-अलग नोड्स पर हैं, इसलिए वे मूल आइटम पर नेटवर्क हॉप से बचना चाहते हैं। इसके बजाय, आप अपने रीड को संभालने के लिए सेकेंडरी इंडेक्स में जितना डेटा चाहिए उतना कॉपी करेंगे।
डायनेमोडीबी में सेकेंडरी इंडेक्स शक्तिशाली हैं, लेकिन उनकी कुछ सीमाएँ हैं। सबसे पहले, वे केवल पढ़ने के लिए हैं - आप सीधे सेकेंडरी इंडेक्स में नहीं लिख सकते। इसके बजाय, आप अपनी मुख्य तालिका में लिखेंगे, और डायनेमोडीबी आपके सेकेंडरी इंडेक्स में प्रतिकृति को संभालेगा। दूसरा, आपसे आपके सेकेंडरी इंडेक्स में लिखने के संचालन के लिए शुल्क लिया जाता है। इस प्रकार, आपकी तालिका में सेकेंडरी इंडेक्स जोड़ने से अक्सर आपकी तालिका के लिए कुल लेखन लागत दोगुनी हो जाएगी।
अब जब हम समझ गए हैं कि सेकेंडरी इंडेक्स क्या हैं और वे कैसे काम करते हैं, तो आइए बात करते हैं कि उन्हें प्रभावी ढंग से कैसे इस्तेमाल किया जाए। सेकेंडरी इंडेक्स एक शक्तिशाली उपकरण हैं, लेकिन उनका दुरुपयोग किया जा सकता है। सेकेंडरी इंडेक्स को प्रभावी ढंग से इस्तेमाल करने के लिए यहाँ कुछ सुझाव दिए गए हैं।
पहली युक्ति स्पष्ट प्रतीत होती है -- द्वितीयक इंडेक्स का उपयोग केवल पढ़ने के लिए किया जा सकता है, इसलिए आपको अपने द्वितीयक इंडेक्स पर केवल पढ़ने के लिए पैटर्न रखने का लक्ष्य रखना चाहिए! और फिर भी, मैं यह गलती हर समय देखता हूँ। डेवलपर्स पहले द्वितीयक इंडेक्स से पढ़ेंगे, फिर मुख्य तालिका में लिखेंगे। इसके परिणामस्वरूप अतिरिक्त लागत और अतिरिक्त विलंब होता है, और आप अक्सर कुछ अग्रिम योजना बनाकर इससे बच सकते हैं।
यदि आपने DynamoDB डेटा मॉडलिंग के बारे में कुछ पढ़ा है, तो आप शायद जानते होंगे कि आपको सबसे पहले अपने एक्सेस पैटर्न के बारे में सोचना चाहिए। यह रिलेशनल डेटाबेस की तरह नहीं है जहाँ आप पहले सामान्यीकृत टेबल डिज़ाइन करते हैं और फिर उन्हें एक साथ जोड़ने के लिए क्वेरी लिखते हैं। DynamoDB में, आपको अपने एप्लिकेशन द्वारा की जाने वाली कार्रवाइयों के बारे में सोचना चाहिए, और फिर उन कार्रवाइयों का समर्थन करने के लिए अपनी टेबल और इंडेक्स डिज़ाइन करना चाहिए।
अपनी तालिका को डिज़ाइन करते समय, मैं सबसे पहले लेखन-आधारित एक्सेस पैटर्न से शुरुआत करना पसंद करता हूँ। अपने लेखन के साथ, मैं अक्सर किसी प्रकार की बाधा बनाए रखता हूँ -- उपयोगकर्ता नाम पर विशिष्टता या समूह में सदस्यों की अधिकतम संख्या। मैं अपनी तालिका को इस तरह से डिज़ाइन करना चाहता हूँ कि यह सरल हो, आदर्श रूप से DynamoDB ट्रांज़ैक्शन का उपयोग किए बिना या रीड-मॉडिफाई-राइट पैटर्न का उपयोग किए बिना जो रेस कंडीशन के अधीन हो सकता है।
जैसे-जैसे आप इन पर काम करेंगे, आपको आम तौर पर पता चलेगा कि आपके आइटम की पहचान करने का एक 'प्राथमिक' तरीका है जो आपके लेखन पैटर्न से मेल खाता है। यह आपकी प्राथमिक कुंजी बन जाएगी। फिर, अतिरिक्त, द्वितीयक पठन पैटर्न को द्वितीयक इंडेक्स के साथ जोड़ना आसान है।
हमारे पहले के उपयोगकर्ता उदाहरण में, प्रत्येक उपयोगकर्ता अनुरोध में संभवतः संगठन और उपयोगकर्ता नाम शामिल होगा। यह मुझे व्यक्तिगत उपयोगकर्ता रिकॉर्ड देखने के साथ-साथ उपयोगकर्ता द्वारा विशिष्ट कार्यों को अधिकृत करने की अनुमति देगा। ईमेल पता लुकअप कम प्रमुख एक्सेस पैटर्न के लिए हो सकता है, जैसे 'पासवर्ड भूल गए' प्रवाह या 'उपयोगकर्ता के लिए खोज' प्रवाह। ये केवल पढ़ने के लिए पैटर्न हैं, और वे एक माध्यमिक सूचकांक के साथ अच्छी तरह से फिट होते हैं।
सेकेंडरी इंडेक्स का उपयोग करने के लिए दूसरा सुझाव यह है कि उन्हें अपने एक्सेस पैटर्न में परिवर्तनशील मानों के लिए उपयोग करें। आइए पहले इसके पीछे के तर्क को समझें, और फिर उन स्थितियों को देखें जहाँ यह लागू होता है।
DynamoDB आपको UpdateItem
ऑपरेशन के साथ किसी मौजूदा आइटम को अपडेट करने की अनुमति देता है। हालाँकि, आप अपडेट में किसी आइटम की प्राथमिक कुंजी नहीं बदल सकते। प्राथमिक कुंजी किसी आइटम के लिए अद्वितीय पहचानकर्ता है, और प्राथमिक कुंजी को बदलना मूल रूप से एक नया आइटम बनाना है। यदि आप किसी मौजूदा आइटम की प्राथमिक कुंजी बदलना चाहते हैं, तो आपको पुराने आइटम को हटाना होगा और एक नया बनाना होगा। यह दो-चरणीय प्रक्रिया धीमी और महंगी है। अक्सर आपको पहले मूल आइटम को पढ़ना होगा, फिर मूल आइटम को हटाने और उसी अनुरोध में एक नया बनाने के लिए लेनदेन का उपयोग करना होगा।
दूसरी ओर, यदि आपके पास द्वितीयक इंडेक्स की प्राथमिक कुंजी में यह परिवर्तनीय मान है, तो प्रतिकृति के दौरान DynamoDB आपके लिए इस डिलीट + क्रिएट प्रक्रिया को संभालेगा। आप मान बदलने के लिए एक सरल UpdateItem
अनुरोध जारी कर सकते हैं, और DynamoDB बाकी को संभाल लेगा।
मैं इस पैटर्न को दो मुख्य स्थितियों में देखता हूँ। पहला, और सबसे आम, तब होता है जब आपके पास एक परिवर्तनशील विशेषता होती है जिसे आप क्रमबद्ध करना चाहते हैं। यहाँ दिए गए विहित उदाहरण एक गेम के लिए लीडरबोर्ड हैं जहाँ लोग लगातार अंक अर्जित कर रहे हैं, या आइटम की लगातार अपडेट होने वाली सूची के लिए जहाँ आप सबसे हाल ही में अपडेट किए गए आइटम को सबसे पहले प्रदर्शित करना चाहते हैं। Google Drive जैसी किसी चीज़ के बारे में सोचें, जहाँ आप अपनी फ़ाइलों को 'अंतिम बार संशोधित' के अनुसार क्रमबद्ध कर सकते हैं।
दूसरा पैटर्न जहां यह तब आता है जब आपके पास एक परिवर्तनशील विशेषता होती है जिसे आप फ़िल्टर करना चाहते हैं। यहां, आप एक ईकॉमर्स स्टोर के बारे में सोच सकते हैं जिसमें किसी उपयोगकर्ता के लिए ऑर्डर का इतिहास होता है। आप उपयोगकर्ता को स्थिति के अनुसार अपने ऑर्डर फ़िल्टर करने की अनुमति देना चाह सकते हैं -- मुझे मेरे सभी ऑर्डर दिखाएं जो 'शिप किए गए' या 'डिलीवर' हैं। आप इसे अपनी पार्टीशन कुंजी या अपनी सॉर्ट कुंजी की शुरुआत में सटीक-मिलान फ़िल्टरिंग की अनुमति देने के लिए बना सकते हैं। जैसे ही आइटम की स्थिति बदलती है, आप स्थिति विशेषता को अपडेट कर सकते हैं और अपने सेकेंडरी इंडेक्स में आइटम को सही ढंग से समूहीकृत करने के लिए डायनेमोडीबी पर निर्भर हो सकते हैं।
इन दोनों स्थितियों में, इस परिवर्तनशील विशेषता को अपने द्वितीयक इंडेक्स में ले जाने से आपका समय और पैसा बचेगा। आप रीड-मॉडिफाई-राइट पैटर्न से बचकर समय बचाएंगे, और आप ट्रांजैक्शन की अतिरिक्त लेखन लागत से बचकर पैसे बचाएंगे।
इसके अतिरिक्त, ध्यान दें कि यह पैटर्न पिछली टिप के साथ अच्छी तरह से फिट बैठता है। यह संभावना नहीं है कि आप परिवर्तनीय विशेषता के आधार पर लिखने के लिए किसी आइटम की पहचान करेंगे जैसे कि उनका पिछला स्कोर, उनकी पिछली स्थिति, या उन्हें आखिरी बार कब अपडेट किया गया था। इसके बजाय, आप उपयोगकर्ता की आईडी, ऑर्डर आईडी, या फ़ाइल की आईडी जैसे अधिक स्थायी मान से अपडेट करेंगे। फिर, आप परिवर्तनीय विशेषता के आधार पर सॉर्ट और फ़िल्टर करने के लिए द्वितीयक इंडेक्स का उपयोग करेंगे।
हमने ऊपर देखा कि DynamoDB आपके डेटा को प्राथमिक कुंजी के आधार पर विभाजनों में विभाजित करता है। DynamoDB का लक्ष्य इन विभाजनों को छोटा रखना है - 10GB या उससे कम - और आपको DynamoDB की स्केलेबिलिटी का लाभ पाने के लिए अपने विभाजनों में अनुरोधों को फैलाने का लक्ष्य रखना चाहिए।
इसका आम तौर पर मतलब है कि आपको अपनी पार्टीशन कुंजी में उच्च-कार्डिनैलिटी मान का उपयोग करना चाहिए। उपयोगकर्ता नाम, ऑर्डर आईडी या सेंसर आईडी जैसी किसी चीज़ के बारे में सोचें। इन विशेषताओं के लिए बड़ी संख्या में मान हैं, और डायनेमोडीबी आपके पार्टीशन में ट्रैफ़िक को फैला सकता है।
अक्सर, मैं देखता हूँ कि लोग अपनी मुख्य तालिका में इस सिद्धांत को समझते हैं, लेकिन फिर अपने द्वितीयक अनुक्रमणिका में इसे पूरी तरह से भूल जाते हैं। अक्सर, वे किसी आइटम के प्रकार के लिए पूरी तालिका में क्रम चाहते हैं। यदि वे उपयोगकर्ताओं को वर्णानुक्रम में प्राप्त करना चाहते हैं, तो वे द्वितीयक अनुक्रमणिका का उपयोग करेंगे जहाँ सभी उपयोगकर्ताओं के पास विभाजन कुंजी के रूप में USERS
और सॉर्ट कुंजी के रूप में उपयोगकर्ता नाम होगा। या, यदि वे किसी ईकॉमर्स स्टोर में सबसे हाल के ऑर्डर का क्रम चाहते हैं, तो वे द्वितीयक अनुक्रमणिका का उपयोग करेंगे जहाँ सभी ऑर्डर में विभाजन कुंजी के रूप में ORDERS
और सॉर्ट कुंजी के रूप में टाइमस्टैम्प होगा।
यह पैटर्न छोटे-ट्रैफ़िक अनुप्रयोगों के लिए काम कर सकता है जहाँ आप DynamoDB विभाजन थ्रूपुट सीमाओं के करीब नहीं आएंगे, लेकिन यह उच्च-ट्रैफ़िक अनुप्रयोग के लिए एक खतरनाक पैटर्न है। आपका सारा ट्रैफ़िक एक ही भौतिक विभाजन में फ़नल हो सकता है, और आप उस विभाजन के लिए लेखन थ्रूपुट सीमाओं को जल्दी से हिट कर सकते हैं।
इसके अलावा, और सबसे खतरनाक बात यह है कि यह आपकी मुख्य तालिका के लिए समस्याएँ पैदा कर सकता है। यदि आपकी द्वितीयक अनुक्रमणिका प्रतिकृति के दौरान लेखन को रोक रही है, तो प्रतिकृति कतार बैकअप ले लेगी। यदि यह कतार बहुत अधिक बैकअप लेती है, तो DynamoDB आपकी मुख्य तालिका पर लेखन को अस्वीकार करना शुरू कर देगा।
यह आपकी मदद करने के लिए डिज़ाइन किया गया है -- DynamoDB आपके सेकेंडरी इंडेक्स की बासीपन को सीमित करना चाहता है, इसलिए यह आपको बड़ी मात्रा में लैग वाले सेकेंडरी इंडेक्स से रोकेगा। हालाँकि, यह एक आश्चर्यजनक स्थिति हो सकती है जो तब सामने आती है जब आप इसकी कम से कम उम्मीद करते हैं।
लोग अक्सर सेकेंडरी इंडेक्स को अपने सभी डेटा को एक नई प्राथमिक कुंजी के साथ दोहराने के तरीके के रूप में सोचते हैं। हालाँकि, आपको अपने सभी डेटा को सेकेंडरी इंडेक्स में समाप्त करने की आवश्यकता नहीं है। यदि आपके पास कोई ऐसा आइटम है जो इंडेक्स की कुंजी स्कीमा से मेल नहीं खाता है, तो उसे इंडेक्स में दोहराया नहीं जाएगा।
यह आपके डेटा पर वैश्विक फ़िल्टर प्रदान करने के लिए वास्तव में उपयोगी हो सकता है। इसके लिए मैं जिस विहित उदाहरण का उपयोग करता हूँ वह एक संदेश इनबॉक्स है। अपनी मुख्य तालिका में, आप किसी विशेष उपयोगकर्ता के लिए सभी संदेशों को उनके बनाए जाने के समय के अनुसार क्रमबद्ध करके संग्रहीत कर सकते हैं।
लेकिन अगर आप मेरी तरह हैं, तो आपके इनबॉक्स में बहुत सारे संदेश हैं। इसके अलावा, आप अपठित संदेशों को 'टू-डू' सूची के रूप में देख सकते हैं, जैसे किसी को जवाब देने के लिए छोटे रिमाइंडर। तदनुसार, मैं आमतौर पर अपने इनबॉक्स में केवल अपठित संदेश देखना चाहता हूँ।
आप इस वैश्विक फ़िल्टर को प्रदान करने के लिए अपने द्वितीयक इंडेक्स का उपयोग कर सकते हैं जहाँ unread == true
। शायद आपकी द्वितीयक इंडेक्स विभाजन कुंजी ${userId}#UNREAD
जैसी कुछ है, और सॉर्ट कुंजी संदेश का टाइमस्टैम्प है। जब आप शुरू में संदेश बनाते हैं, तो इसमें द्वितीयक इंडेक्स विभाजन कुंजी मान शामिल होगा और इस प्रकार इसे अपठित संदेशों के द्वितीयक इंडेक्स में दोहराया जाएगा। बाद में, जब कोई उपयोगकर्ता संदेश पढ़ता है, तो आप status
को READ
में बदल सकते हैं और द्वितीयक इंडेक्स विभाजन कुंजी मान को हटा सकते हैं। फिर DynamoDB इसे आपके द्वितीयक इंडेक्स से हटा देगा।
मैं इस तरकीब का हर समय इस्तेमाल करता हूँ, और यह उल्लेखनीय रूप से प्रभावी है। इसके अलावा, एक विरल इंडेक्स आपको पैसे बचाएगा। संदेशों को पढ़ने के लिए कोई भी अपडेट सेकेंडरी इंडेक्स में दोहराया नहीं जाएगा, और आप लिखने की लागत बचाएंगे।
हमारी आखिरी सलाह के लिए, आइए पिछले बिंदु को थोड़ा और आगे ले चलते हैं। हमने अभी देखा कि अगर आइटम में इंडेक्स के लिए प्राथमिक कुंजी तत्व नहीं हैं, तो DynamoDB आपके सेकेंडरी इंडेक्स में आइटम को शामिल नहीं करेगा। इस ट्रिक का इस्तेमाल न केवल प्राथमिक कुंजी तत्वों के लिए बल्कि डेटा में गैर-कुंजी विशेषताओं के लिए भी किया जा सकता है!
जब आप कोई द्वितीयक इंडेक्स बनाते हैं, तो आप यह निर्दिष्ट कर सकते हैं कि मुख्य तालिका से कौन सी विशेषताएँ आप द्वितीयक इंडेक्स में शामिल करना चाहते हैं। इसे इंडेक्स का प्रक्षेपण कहा जाता है। आप मुख्य तालिका से सभी विशेषताएँ, केवल प्राथमिक कुंजी विशेषताएँ या विशेषताओं का एक उपसमूह शामिल करना चुन सकते हैं।
हालाँकि आपके सेकेंडरी इंडेक्स में सभी विशेषताओं को शामिल करना आकर्षक है, लेकिन यह एक महंगी गलती हो सकती है। याद रखें कि आपके मुख्य टेबल में हर लेखन जो किसी अनुमानित विशेषता के मान को बदलता है, उसे आपके सेकेंडरी इंडेक्स में दोहराया जाएगा। पूर्ण प्रक्षेपण वाला एक एकल सेकेंडरी इंडेक्स प्रभावी रूप से आपकी टेबल के लिए लेखन लागत को दोगुना कर देता है। प्रत्येक अतिरिक्त सेकेंडरी इंडेक्स आपकी लेखन लागत को 1/N + 1
से बढ़ाता है, जहाँ N
नए इंडेक्स से पहले सेकेंडरी इंडेक्स की संख्या है।
इसके अतिरिक्त, आपकी लेखन लागत की गणना आपके आइटम के आकार के आधार पर की जाती है। आपकी तालिका में लिखे गए प्रत्येक 1KB डेटा के लिए WCU का उपयोग किया जाता है। यदि आप अपने द्वितीयक इंडेक्स में 4KB आइटम की प्रतिलिपि बना रहे हैं, तो आपको अपनी मुख्य तालिका और अपने द्वितीयक इंडेक्स दोनों पर पूरे 4 WCU का भुगतान करना होगा।
इस प्रकार, दो तरीके हैं जिनसे आप अपने सेकेंडरी इंडेक्स प्रोजेक्शन को कम करके पैसे बचा सकते हैं। सबसे पहले, आप कुछ खास राइट्स को पूरी तरह से टाल सकते हैं। यदि आपके पास कोई अपडेट ऑपरेशन है जो आपके सेकेंडरी इंडेक्स प्रोजेक्शन में किसी भी विशेषता को नहीं छूता है, तो डायनेमोडीबी आपके सेकेंडरी इंडेक्स में राइट को छोड़ देगा। दूसरा, उन राइट्स के लिए जो आपके सेकेंडरी इंडेक्स में रिप्लिकेट करते हैं, आप रिप्लिकेट किए गए आइटम के आकार को कम करके पैसे बचा सकते हैं।
यह संतुलन सही तरीके से बनाना मुश्किल हो सकता है। इंडेक्स बनने के बाद सेकेंडरी इंडेक्स प्रोजेक्शन में बदलाव नहीं किया जा सकता। अगर आपको लगता है कि आपको अपने सेकेंडरी इंडेक्स में अतिरिक्त विशेषताओं की ज़रूरत है, तो आपको नए प्रोजेक्शन के साथ एक नया इंडेक्स बनाना होगा और फिर पुराने इंडेक्स को हटाना होगा।
अब जबकि हमने द्वितीयक सूचकांकों के बारे में कुछ व्यावहारिक सलाह जान ली है, तो आइए एक कदम पीछे हटें और एक अधिक मौलिक प्रश्न पूछें - क्या आपको द्वितीयक सूचकांक का उपयोग करना चाहिए?
जैसा कि हमने देखा है, सेकेंडरी इंडेक्स आपको अपने डेटा को अलग तरीके से एक्सेस करने में मदद करते हैं। हालाँकि, यह अतिरिक्त लेखन की कीमत पर आता है। इसलिए, सेकेंडरी इंडेक्स के लिए मेरा नियम यह है:
जब कम हुई पठन लागत, बढ़ी हुई लेखन लागत से अधिक हो, तो द्वितीयक अनुक्रमणिका का उपयोग करें।
जब आप ऐसा कहते हैं तो यह स्पष्ट लगता है, लेकिन जब आप मॉडलिंग कर रहे होते हैं तो यह विरोधाभासी हो सकता है। अन्य तरीकों के बारे में सोचे बिना "इसे एक द्वितीयक सूचकांक में डालें" कहना बहुत आसान लगता है।
इस बात को स्पष्ट करने के लिए, आइए दो स्थितियों पर नजर डालें जहां द्वितीयक सूचकांकों का कोई मतलब नहीं हो सकता है।
डायनेमोडीबी के साथ, आप आम तौर पर चाहते हैं कि आपकी प्राथमिक कुंजियाँ आपके लिए फ़िल्टरिंग करें। जब भी मैं डायनेमोडीबी में क्वेरी का उपयोग करता हूं, लेकिन फिर अपने एप्लिकेशन में अपनी फ़िल्टरिंग करता हूं, तो यह मुझे थोड़ा परेशान करता है - मैं इसे प्राथमिक कुंजी में क्यों नहीं बना सकता?
मेरी सहज प्रतिक्रिया के बावजूद, ऐसी कुछ स्थितियाँ होती हैं जहाँ आप अपने डेटा को अधिक पढ़ना चाहेंगे और फिर अपने आवेदन में उसे फ़िल्टर करना चाहेंगे।
सबसे आम जगह जहां आप इसे देखेंगे, वह तब है जब आप अपने उपयोगकर्ताओं के लिए अपने डेटा पर बहुत सारे अलग-अलग फ़िल्टर प्रदान करना चाहते हैं, लेकिन प्रासंगिक डेटा सेट सीमित है।
वर्कआउट ट्रैकर के बारे में सोचें। आप उपयोगकर्ताओं को कई विशेषताओं पर फ़िल्टर करने की अनुमति देना चाह सकते हैं, जैसे कि वर्कआउट का प्रकार, तीव्रता, अवधि, तिथि, इत्यादि। हालाँकि, उपयोगकर्ता के पास वर्कआउट की संख्या प्रबंधनीय होगी - यहाँ तक कि एक पावर यूजर को भी 1000 वर्कआउट पार करने में कुछ समय लगेगा। इन सभी विशेषताओं पर इंडेक्स लगाने के बजाय, आप बस उपयोगकर्ता के सभी वर्कआउट प्राप्त कर सकते हैं और फिर अपने एप्लिकेशन में फ़िल्टर कर सकते हैं।
यहीं पर मैं गणित करने की सलाह देता हूं। डायनेमोडीबी इन दो विकल्पों की गणना करना आसान बनाता है और यह बताता है कि आपके एप्लिकेशन के लिए कौन सा विकल्प बेहतर काम करेगा।
चलिए अपनी स्थिति को थोड़ा बदलते हैं -- क्या होगा अगर हमारा आइटम कलेक्शन बड़ा है? क्या होगा अगर हम जिम के लिए वर्कआउट ट्रैकर बना रहे हैं, और हम जिम के मालिक को जिम में सभी उपयोगकर्ताओं के लिए ऊपर बताई गई सभी विशेषताओं को फ़िल्टर करने की अनुमति देना चाहते हैं?
इससे स्थिति बदल जाती है। अब हम सैकड़ों या हज़ारों उपयोगकर्ताओं के बारे में बात कर रहे हैं, जिनमें से प्रत्येक के पास सैकड़ों या हज़ारों वर्कआउट हैं। संपूर्ण आइटम संग्रह को बार-बार पढ़ना और परिणामों पर पोस्ट-हॉक फ़िल्टरिंग करना समझदारी नहीं होगी।
लेकिन सेकेंडरी इंडेक्स का यहां भी कोई मतलब नहीं है। सेकेंडरी इंडेक्स ज्ञात एक्सेस पैटर्न के लिए अच्छे हैं, जहां आप प्रासंगिक फ़िल्टर की मौजूदगी पर भरोसा कर सकते हैं। अगर हम चाहते हैं कि हमारा जिम मालिक कई तरह की विशेषताओं पर फ़िल्टर कर सके, जो सभी वैकल्पिक हैं, तो हमें इसे काम करने के लिए बड़ी संख्या में इंडेक्स बनाने की ज़रूरत होगी।
हमने पहले क्वेरी प्लानर के संभावित नुकसानों के बारे में बात की थी, लेकिन क्वेरी प्लानर के फायदे भी हैं। अधिक लचीली क्वेरीज़ की अनुमति देने के अलावा, वे इन क्वेरीज़ को बनाने में कई इंडेक्स से आंशिक परिणामों को देखने के लिए इंडेक्स इंटरसेक्शन जैसी चीज़ें भी कर सकते हैं। आप डायनेमोडीबी के साथ भी यही काम कर सकते हैं, लेकिन इसके परिणामस्वरूप आपके एप्लिकेशन के साथ बहुत सारे आगे-पीछे होने वाले काम होंगे, साथ ही इसे समझने के लिए कुछ जटिल एप्लिकेशन लॉजिक भी होंगे।
जब मुझे इस तरह की समस्याएँ होती हैं, तो मैं आमतौर पर इस उपयोग के मामले के लिए बेहतर उपकरण की तलाश करता हूँ। रॉकसेट और इलास्टिकसर्च यहाँ आपके डेटासेट में लचीली, सेकेंडरी-इंडेक्स जैसी फ़िल्टरिंग प्रदान करने के लिए मेरी पसंदीदा सिफारिशें हैं।
इस पोस्ट में, हमने DynamoDB सेकेंडरी इंडेक्स के बारे में सीखा। सबसे पहले, हमने DynamoDB कैसे काम करता है और सेकेंडरी इंडेक्स की आवश्यकता क्यों है, यह समझने के लिए कुछ वैचारिक बिट्स को देखा। फिर, हमने सेकेंडरी इंडेक्स का प्रभावी ढंग से उपयोग करने और उनकी विशिष्ट विशेषताओं को जानने के लिए कुछ व्यावहारिक सुझावों की समीक्षा की। अंत में, हमने देखा कि सेकेंडरी इंडेक्स के बारे में कैसे सोचना है ताकि यह पता चल सके कि आपको कब अन्य तरीकों का उपयोग करना चाहिए।
सेकेंडरी इंडेक्स आपके DynamoDB टूलबॉक्स में एक शक्तिशाली उपकरण हैं, लेकिन वे कोई सिल्वर बुलेट नहीं हैं। सभी DynamoDB डेटा मॉडलिंग के साथ, सुनिश्चित करें कि आप अपने एक्सेस पैटर्न पर ध्यान से विचार करें और शुरू करने से पहले लागतों की गणना करें।
एलेक्स डेब्री के ब्लॉग डायनेमोडीबी फ़िल्टरिंग और एग्रीगेशन क्वेरीज़ यूज़िंग एसक्यूएल ऑन रॉकसेट में आप द्वितीयक-सूचकांक-जैसी फ़िल्टरिंग के लिए रॉकसेट का उपयोग कैसे कर सकते हैं, इसके बारे में अधिक जानें।