फ़िल्टर किए गए अनुक्रमणिका आश्चर्यजनक रूप से शक्तिशाली होते हैं, लेकिन मुझे अभी भी उनके बारे में कुछ भ्रम दिखाई देता है - विशेष रूप से उन स्तंभों के बारे में जो फ़िल्टर में उपयोग किए जाते हैं, और जब आप फ़िल्टर को कसना चाहते हैं तो क्या होता है।
dba.stackexchange पर हाल ही में एक प्रश्न ने इस बारे में सहायता मांगी कि फ़िल्टर किए गए अनुक्रमणिका के फ़िल्टर में उपयोग किए जाने वाले कॉलम को अनुक्रमणिका के 'शामिल' कॉलम में क्यों शामिल किया जाना चाहिए। उत्कृष्ट प्रश्न - सिवाय इसके कि मुझे लगा कि यह एक खराब आधार पर शुरू हुआ, क्योंकि उन स्तंभों को सूचकांक में शामिल नहीं किया जाना चाहिए . हाँ, वे मदद करते हैं, लेकिन उस तरीके से नहीं जिस तरह से सवाल सुझाव दे रहा था।
प्रश्न को देखते हुए आपको बचाने के लिए, यहां एक त्वरित सारांश दिया गया है:
इस प्रश्न को संतुष्ट करने के लिए…
SELECT Id, DisplayName FROM Users WHERE Reputation > 400000;
…निम्न फ़िल्टर्ड अनुक्रमणिका बहुत अच्छी है:
CREATE UNIQUE NONCLUSTERED INDEX Users_400k_Club ON dbo.Users ( DisplayName, Id ) INCLUDE ( Reputation ) WHERE Reputation > 400000;
लेकिन इस इंडेक्स के होने के बावजूद, क्वेरी ऑप्टिमाइज़र निम्नलिखित इंडेक्स की अनुशंसा करता है यदि फ़िल्टर किए गए मान को 450000 तक कड़ा कर दिया जाता है।
CREATE NONCLUSTERED INDEX IndexThatWasMissing ON dbo.Users ( Reputation ) INCLUDE ( DisplayName, Id );
मैं यहां प्रश्न को थोड़ा सा समझा रहा हूं, जो इस स्थिति का जिक्र करते हुए शुरू होता है और फिर एक अलग उदाहरण बनाता है, लेकिन विचार वही है। मैं बस एक अलग तालिका शामिल करके चीजों को और अधिक जटिल नहीं बनाना चाहता था।
बिंदु है - क्यूओ द्वारा सुझाया गया सूचकांक मूल सूचकांक है लेकिन इसके सिर पर मुड़ा हुआ है। मूल इंडेक्स में शामिल सूची में प्रतिष्ठा थी, और डिस्प्लेनाम और आईडी प्रमुख कॉलम के रूप में थे, जबकि नया अनुशंसित इंडेक्स कुंजी कॉलम के रूप में प्रतिष्ठा और INCLUDE में डिस्प्लेनाम और आईडी के विपरीत है। आइए देखें क्यों।
प्रश्न एरिक डार्लिंग की एक पोस्ट को संदर्भित करता है, जहां वह बताता है कि उसने प्रतिष्ठा को INCLUDE कॉलम में डालकर उपरोक्त '450,000' क्वेरी को ट्यून किया है। एरिक दिखाता है कि INCLUDE सूची में प्रतिष्ठा के बिना, एक क्वेरी जो प्रतिष्ठा के उच्च मूल्य को फ़िल्टर करती है, उसे लुकअप (खराब!) उन्होंने निष्कर्ष निकाला कि INCLUDE सूची में प्रतिष्ठा कॉलम होने से SQL के पास आँकड़े होते हैं, ताकि वह बेहतर विकल्प बना सके, और यह दर्शाता है कि INCLUDE में प्रतिष्ठा के साथ विभिन्न प्रकार के प्रश्न जो उच्च प्रतिष्ठा मूल्यों पर सभी फ़िल्टर करते हैं, सभी उसके फ़िल्टर किए गए इंडेक्स को स्कैन करते हैं।पी>
dba.stackexchange प्रश्न के उत्तर में, ब्रेंट ओज़र बताते हैं कि एरिक के सुधार विशेष रूप से महान नहीं हैं क्योंकि वे स्कैन का कारण बनते हैं। मैं उस पर वापस आता हूँ, क्योंकि यह अपने आप में एक दिलचस्प बिंदु है, और कुछ हद तक गलत है।
आइए पहले सामान्य रूप से अनुक्रमणिका के बारे में थोड़ा सोचें।
एक सूचकांक डेटा के एक सेट को एक आदेशित संरचना प्रदान करता है। (मैं पांडित्यपूर्ण हो सकता हूं और इंगित कर सकता हूं कि शुरू से अंत तक एक इंडेक्स में डेटा के माध्यम से पढ़ना आपको एक पृष्ठ से दूसरे पृष्ठ पर एक अजीब तरीके से कूद सकता है, लेकिन फिर भी जब आप पृष्ठों के माध्यम से पढ़ रहे हैं, तो एक पृष्ठ से पॉइंटर्स का अनुसरण करते हुए अगले आप आश्वस्त हो सकते हैं कि डेटा का आदेश दिया गया है। प्रत्येक पृष्ठ के भीतर आप डेटा को क्रम में पढ़ने के लिए इधर-उधर कूद भी सकते हैं, लेकिन एक सूची है जो आपको दिखाती है कि पृष्ठ के किन हिस्सों (स्लॉट) को किस क्रम में पढ़ा जाना चाहिए। वास्तव में मेरे पांडित्य का कोई मतलब नहीं है सिवाय उन समान पांडित्य को जवाब देने के जो अगर मैं नहीं करता तो टिप्पणी करेंगे।)
और यह क्रम प्रमुख स्तंभों के अनुसार है - यही आसान बिट है जो सभी को मिलता है। यह न केवल बाद में डेटा को पुन:क्रमित करने से बचने में सक्षम होने के लिए उपयोगी है, बल्कि उन स्तंभों द्वारा किसी विशेष पंक्ति या पंक्तियों की श्रेणी का शीघ्रता से पता लगाने में सक्षम होने के लिए भी उपयोगी है।
इंडेक्स के लीफ स्तरों में शामिल सूची में किसी भी कॉलम में मान होते हैं, या क्लस्टर इंडेक्स के मामले में, तालिका में सभी कॉलम (गैर-स्थायी गणना कॉलम को छोड़कर) के मान होते हैं। इंडेक्स में अन्य स्तरों में केवल कुंजी कॉलम होते हैं और (यदि इंडेक्स अद्वितीय नहीं है) पंक्ति का अद्वितीय पता - जो क्लस्टर इंडेक्स की कुंजी है (पंक्ति के यूनीकिफायर के साथ यदि क्लस्टर इंडेक्स अद्वितीय नहीं है या तो ) या ढेर के लिए RowID मान, पंक्ति के लिए अन्य सभी कॉलम मानों तक आसान पहुंच की अनुमति देने के लिए पर्याप्त है। पत्ती के स्तर में सभी 'पता' जानकारी भी शामिल होती है।
लेकिन यह इस पोस्ट के लिए दिलचस्प बात नहीं है। इस पोस्ट के लिए दिलचस्प बात यह है कि मेरा मतलब "डेटा के एक सेट से" है। याद रखें मैंने कहा था "एक अनुक्रमणिका डेटा के एक सेट के लिए एक आदेशित संरचना प्रदान करती है ".
क्लस्टर्ड इंडेक्स में, डेटा का वह सेट पूरी तालिका है, लेकिन यह कुछ और हो सकता है। आप शायद पहले से ही यह देख सकते हैं कि अधिकांश गैर-संकुल अनुक्रमणिका तालिका के सभी स्तंभों को कैसे शामिल नहीं करते हैं। यह उन चीजों में से एक है जो गैर-संकुल अनुक्रमणिका को इतना उपयोगी बनाती है, क्योंकि वे आम तौर पर अंतर्निहित तालिका से बहुत छोटी होती हैं।
अनुक्रमित दृश्य के मामले में, हमारे डेटा का सेट यह एक संपूर्ण क्वेरी का परिणाम हो सकता है, जिसमें कई तालिकाओं में शामिल होना शामिल है! वह एक और पोस्ट के लिए है।
लेकिन फ़िल्टर किए गए अनुक्रमणिका में, यह न केवल स्तंभों के सबसेट की एक प्रति है, बल्कि पंक्तियों का एक सबसेट भी है। तो यहां उदाहरण में, सूचकांक केवल 400k से अधिक प्रतिष्ठा वाले उपयोगकर्ताओं के लिए है।
CREATE UNIQUE NONCLUSTERED INDEX Users_400k_Club_NoInclude ON dbo.Users ( DisplayName, Id ) WHERE Reputation > 400000;
यह अनुक्रमणिका 400k से अधिक प्रतिष्ठा वाले उपयोगकर्ताओं को लेती है, और उन्हें DisplayName और Id द्वारा आदेश देती है। यह अद्वितीय हो सकता है क्योंकि (माना जाता है) आईडी कॉलम पहले से ही अद्वितीय है। अगर आप अपनी टेबल पर ऐसा ही कुछ करने की कोशिश करते हैं, तो आपको इससे सावधान रहने की आवश्यकता हो सकती है।
लेकिन इस बिंदु पर, सूचकांक परवाह नहीं है कि प्रत्येक उपयोगकर्ता के लिए प्रतिष्ठा क्या है - यह सिर्फ इस बात की परवाह करता है कि प्रतिष्ठा सूचकांक में होने के लिए पर्याप्त है या नहीं। यदि किसी उपयोगकर्ता की प्रतिष्ठा अपडेट हो जाती है और वह उस सीमा से अधिक सुझाव देता है कि उपयोगकर्ता का DisplayName और Id अनुक्रमणिका में डाला जाएगा। यदि यह नीचे चला जाता है, तो इसे अनुक्रमणिका से हटा दिया जाएगा। यह उच्च रोलर्स के लिए एक अलग तालिका की तरह है, सिवाय इसके कि हम अंतर्निहित तालिका में 400k सीमा से अधिक प्रतिष्ठा मूल्य बढ़ाकर उस तालिका में लोगों को प्राप्त करते हैं। यह वास्तव में प्रतिष्ठा मूल्य को संग्रहीत किए बिना ऐसा कर सकता है।
तो अब अगर हम 450k से अधिक सीमा वाले लोगों को ढूंढना चाहते हैं, तो उस अनुक्रमणिका में कुछ जानकारी गुम है।
निश्चित रूप से, हम विश्वास के साथ कह सकते हैं कि हम जो भी पाएंगे वह उस इंडेक्स में है - लेकिन इंडेक्स में प्रतिष्ठा पर आगे फ़िल्टर करने के लिए पर्याप्त जानकारी नहीं है। अगर मैंने आपसे कहा कि मेरे पास 1990 के दशक की सर्वश्रेष्ठ पिक्चर ऑस्कर विजेता फिल्मों की वर्णमाला सूची थी (अमेरिकन ब्यूटी, ब्रेवहार्ट, डांस विद वोल्व्स, इंग्लिश पेशेंट, फॉरेस्ट गंप, शिंडलर्स लिस्ट, शेक्सपियर इन लव, साइलेंस ऑफ द लैम्ब्स, टाइटैनिक, अनफॉरगिवेन) , तो मैं आपको आश्वस्त कर सकता हूं कि 1994-1996 के विजेता उनमें से एक उपसमुच्चय होंगे, लेकिन मैं पहले कुछ और जानकारी प्राप्त किए बिना प्रश्न का उत्तर नहीं दे सकता।
स्पष्ट रूप से मेरा फ़िल्टर्ड इंडेक्स अधिक उपयोगी होगा यदि मैंने वर्ष शामिल किया था, और संभावित रूप से और भी अधिक यदि वर्ष एक महत्वपूर्ण कॉलम था, क्योंकि मेरी नई क्वेरी 1994-1996 के लिए खोजना चाहती है। लेकिन मैंने शायद इस इंडेक्स को 1990 के दशक की सभी फिल्मों को वर्णानुक्रम में सूचीबद्ध करने के लिए एक क्वेरी के आसपास डिज़ाइन किया था। यह प्रश्न इस बात की परवाह नहीं करता है कि वास्तविक वर्ष क्या है, केवल यह 1990 के दशक में है या नहीं, और मुझे वर्ष वापस करने की भी आवश्यकता नहीं है - केवल शीर्षक - इसलिए मैं परिणाम प्राप्त करने के लिए अपने फ़िल्टर किए गए अनुक्रमणिका को स्कैन कर सकता हूं। उस क्वेरी के लिए मुझे परिणामों को फिर से व्यवस्थित करने या शुरुआती बिंदु खोजने की भी आवश्यकता नहीं है - मेरी अनुक्रमणिका वास्तव में एकदम सही है।
फ़िल्टर में कॉलम के मान की परवाह न करने का एक अधिक व्यावहारिक उदाहरण स्थिति पर है, जैसे:
WHERE IsActive = 1
मैं अक्सर कोड देखता हूं जो पंक्तियों को 'सक्रिय' होने पर डेटा को एक तालिका से दूसरी तालिका में ले जाता है। लोग नहीं चाहते कि पुरानी पंक्तियाँ उनकी तालिका को अस्त-व्यस्त कर दें, और वे मानते हैं कि उनका 'हॉट' डेटा उनके सभी डेटा का केवल एक छोटा उपसमूह है। इसलिए वे अपनी सक्रिय तालिका को छोटा रखते हुए अपने कूलिंग डेटा को एक संग्रह तालिका में स्थानांतरित कर देते हैं।
एक फ़िल्टर्ड इंडेक्स आपके लिए यह कर सकता है। पर्दे के पीछे। जैसे ही आप पंक्ति को अपडेट करते हैं और उस IsActive कॉलम को 1 के अलावा किसी अन्य चीज़ में बदलते हैं। यदि आप केवल अपने अधिकांश इंडेक्स में सक्रिय डेटा रखने की परवाह करते हैं, तो फ़िल्टर किए गए इंडेक्स आदर्श होते हैं। यदि IsActive मान वापस 1 में बदल जाता है, तो यह पंक्तियों को वापस अनुक्रमणिका में भी लाएगा।
लेकिन आपको इसे प्राप्त करने के लिए INCLUDE सूची में IsActive डालने की आवश्यकता नहीं है। आप मूल्य को क्यों स्टोर करना चाहेंगे - आप पहले से ही जानते हैं कि मूल्य क्या है - यह 1 है! जब तक आप उस मूल्य को वापस करने के लिए नहीं कह रहे हैं जिसकी आपको आवश्यकता नहीं है। और जब आप पहले से ही जानते हैं कि उत्तर 1 है, तो आप मूल्य क्यों वापस करेंगे?! सिवाय इसके कि निराशाजनक रूप से, एरिक ने अपने पोस्ट में जिन आंकड़ों का उल्लेख किया है, वे INCLUDE सूची में होने का लाभ उठाएंगे। आपको क्वेरी के लिए इसकी आवश्यकता नहीं है, लेकिन आपको इसे आँकड़ों के लिए शामिल करना चाहिए।
आइए इस बारे में सोचें कि किसी अनुक्रमणिका की उपयोगिता का पता लगाने के लिए क्वेरी ऑप्टिमाइज़र को क्या करने की आवश्यकता है।
इससे पहले कि यह बहुत कुछ कर सके, यह विचार करने की जरूरत है कि क्या सूचकांक एक उम्मीदवार है। किसी अनुक्रमणिका का उपयोग करने का कोई मतलब नहीं है यदि उसमें वे सभी पंक्तियाँ नहीं हैं जिनकी आवश्यकता हो सकती है - तब तक नहीं जब तक कि हमारे पास शेष प्राप्त करने का एक प्रभावी तरीका न हो। अगर मुझे 1985-1995 की फिल्में चाहिए, तो 1990 के दशक की फिल्मों की मेरी सूची बहुत ही बेकार है। लेकिन 1994-1996 के लिए, शायद यह बुरा नहीं है।
इस बिंदु पर, किसी भी सूचकांक विचार की तरह, मुझे इस बारे में सोचने की ज़रूरत है कि क्या यह डेटा को खोजने और इसे एक ऐसे क्रम में लाने में मदद करेगा जो बाकी क्वेरी को निष्पादित करने में मदद करेगा (संभवतः मर्ज जॉइन, स्ट्रीम एग्रीगेट, संतोषजनक के लिए) एक आदेश द्वारा, या विभिन्न अन्य कारणों से)। यदि मेरा क्वेरी फ़िल्टर इंडेक्स फ़िल्टर से बिल्कुल मेल खाता है, तो मुझे और फ़िल्टर करने की आवश्यकता नहीं है - केवल इंडेक्स का उपयोग करना पर्याप्त है। यह बहुत अच्छा लगता है, लेकिन अगर यह बिल्कुल मेल नहीं खाता है, अगर मेरा क्वेरी फ़िल्टर सख्त है कि इंडेक्स फ़िल्टर (जैसे मेरा 1994-1996 उदाहरण, या एरिक का 450,000), मुझे उन वर्ष के मूल्यों या प्रतिष्ठा मूल्यों की आवश्यकता होगी जाँच करने के लिए - उम्मीद है कि उन्हें या तो लीफ स्तर पर शामिल किए गए से या मेरे प्रमुख कॉलम में कहीं से प्राप्त किया जा रहा है। यदि वे अनुक्रमणिका में नहीं हैं, तो मुझे अपने फ़िल्टर किए गए अनुक्रमणिका में प्रत्येक पंक्ति के लिए एक लुकअप करना होगा (और आदर्श रूप से, मेरे लुकअप को कितनी बार कॉल किया जाएगा, इसके बारे में एक विचार है, जो कि एरिक चाहता है कि आँकड़े हैं के लिए शामिल कॉलम)।
आदर्श रूप से, मेरे द्वारा उपयोग की जाने वाली किसी भी अनुक्रमणिका को सही ढंग से (चाबियों के माध्यम से) आदेश दिया जाता है, जिसमें मुझे वापस आने के लिए आवश्यक सभी कॉलम शामिल होते हैं, और केवल उन पंक्तियों के लिए पूर्व-फ़िल्टर किया जाता है जिनकी मुझे आवश्यकता होती है। यह एकदम सही अनुक्रमणिका होगी, और मेरी निष्पादन योजना एक स्कैन होगी।
यह सही है, एक स्कैन। सीक नहीं, बल्कि स्कैन। यह मेरी अनुक्रमणिका के पहले पृष्ठ पर शुरू होगा और मुझे तब तक पंक्तियाँ देता रहेगा जब तक कि मुझे जितनी आवश्यकता हो उतनी न मिल जाए, या जब तक लौटने के लिए और पंक्तियाँ न हों। किसी को छोड़ना नहीं, उन्हें छांटना नहीं - बस मुझे पंक्तियों को क्रम में देना।
एक सीक सुझाव देगा कि मुझे पूरे सूचकांक की आवश्यकता नहीं है, जिसका अर्थ है कि मैं सूचकांक के उस हिस्से को बनाए रखने में संसाधनों को बर्बाद कर रहा हूं, और इसे पूछने के लिए मुझे शुरुआती बिंदु ढूंढना होगा और यह देखने के लिए पंक्तियों की जांच करनी होगी कि क्या मैंने किया है अंत मारा या नहीं। यदि मेरे स्कैन में एक विधेय है, तो निश्चित रूप से, मुझे अपनी आवश्यकता से अधिक डेटा देखना (और परीक्षण) करना पड़ रहा है, लेकिन यदि मेरे अनुक्रमणिका फ़िल्टर सही हैं, तो क्वेरी ऑप्टिमाइज़र को इसे पहचानना चाहिए और उन जाँचों को नहीं करना चाहिए ।
अंतिम विचार
फ़िल्टर किए गए इंडेक्स के लिए INCLUDEs महत्वपूर्ण नहीं हैं। वे कॉलम तक आसान पहुंच प्रदान करने के लिए उपयोगी हैं जो आपकी क्वेरी के लिए उपयोगी हो सकते हैं, और यदि आप किसी भी कॉलम द्वारा अपने फ़िल्टर किए गए इंडेक्स में क्या है, चाहे वह फ़िल्टर में उल्लिखित हो या नहीं, तो आपको उस कॉलम को अंदर रखने पर विचार करना चाहिए मिश्रित होना। लेकिन उस समय आपको यह पूछना चाहिए कि क्या आपकी अनुक्रमणिका का फ़िल्टर सही है, आपकी शामिल सूची में आपके पास और क्या होना चाहिए, और यहां तक कि कुंजी कॉलम क्या होना चाहिए। एरिक के प्रश्न ठीक से नहीं चल रहे थे क्योंकि उसे ऐसी जानकारी की आवश्यकता थी जो अनुक्रमणिका में नहीं थी, भले ही उसने फ़िल्टर में कॉलम का उल्लेख किया हो। उन्होंने आँकड़ों के लिए भी एक अच्छा उपयोग पाया, और मैं अब भी आपको इस कारण से फ़िल्टर कॉलम शामिल करने के लिए प्रोत्साहित करता हूँ। लेकिन उन्हें एक INCLUDE में डालने से वे अचानक सीक करना शुरू नहीं कर सकते, क्योंकि ऐसा कोई इंडेक्स काम नहीं करता है, चाहे फ़िल्टर किया गया हो या नहीं।
मैं चाहता हूं कि आप, पाठक, फ़िल्टर किए गए इंडेक्स को वास्तव में अच्छी तरह से समझें। वे अविश्वसनीय रूप से उपयोगी हैं और, जब आप उन्हें अपने अधिकारों में तालिकाओं की तरह चित्रित करना शुरू करते हैं, तो आपके समग्र डेटाबेस डिज़ाइन का हिस्सा बन सकते हैं। वे हमेशा ANSI_NULLs और QUOTED_IDENTIFIER सेटिंग्स का उपयोग करने का एक कारण भी हैं, क्योंकि जब तक वे सेटिंग चालू नहीं होती हैं, तब तक आपको फ़िल्टर किए गए अनुक्रमणिका से त्रुटियां मिलेंगी, लेकिन उम्मीद है कि आप पहले से ही सुनिश्चित कर लें कि वे हमेशा चालू हैं।
ओह, और वे फिल्में थीं फॉरेस्ट गंप, ब्रेवहार्ट, और द इंग्लिश पेशेंट।
@rob_farley