मुझे गलत मत समझो; मुझे फ़िल्टर्ड इंडेक्स पसंद हैं। वे I/O के अधिक कुशल उपयोग के अवसर पैदा करते हैं, और अंत में हमें उचित ANSI- अनुरूप अद्वितीय बाधाओं को लागू करने की अनुमति देते हैं (जहां एक से अधिक NULL की अनुमति है)। हालांकि, वे परिपूर्ण से बहुत दूर हैं। मैं कुछ ऐसे क्षेत्रों को इंगित करना चाहता था जहां फ़िल्टर किए गए अनुक्रमणिका में सुधार किया जा सकता है और वहां वर्कलोड के एक बड़े हिस्से के लिए उन्हें अधिक उपयोगी और व्यावहारिक बनाया जा सकता है।
सबसे पहले, खुशखबरी
फ़िल्टर किए गए इंडेक्स पहले के महंगे प्रश्नों का बहुत तेज़ काम कर सकते हैं, और कम जगह का उपयोग करके ऐसा कर सकते हैं (और इसलिए स्कैन किए जाने पर भी I/O कम हो जाते हैं)।
Sales.SalesOrderDetailEnlarged
. का उपयोग करके एक त्वरित उदाहरण (जोनाथन केहैयस (@SQLPoolBoy) द्वारा इस स्क्रिप्ट का उपयोग करके बनाया गया है)। इस तालिका में 4.8MM पंक्तियाँ हैं, जिसमें 587 MB डेटा और 363 MB अनुक्रमणिकाएँ हैं। केवल एक अशक्त स्तंभ है, CarrierTrackingNumber
, तो चलिए उसके साथ खेलते हैं। जैसा कि, तालिका में वर्तमान में इनमें से लगभग आधे मान (2.4MM) NULL के रूप में हैं। मैं एक परिदृश्य को अनुकरण करने के लिए इसे लगभग 240K तक कम करने जा रहा हूं जहां तालिका में पंक्तियों का एक छोटा प्रतिशत वास्तव में एक इंडेक्स के लिए योग्य है, ताकि फ़िल्टर किए गए इंडेक्स के लाभों को सर्वोत्तम रूप से हाइलाइट किया जा सके। निम्न क्वेरी 2.17MM पंक्तियों को प्रभावित करती है, 241,507 पंक्तियों को CarrierTrackingNumber
के लिए NULL मान के साथ छोड़ देती है :
अपडेट सेल्स.सेल्सऑर्डरडिटेलएनलार्जेडसेट कैरियरट्रैकिंगनंबर ='एक्स' जहां कैरियरट्रैकिंगनंबर शून्य है और सेल्सऑर्डरआईडी% 10 <> 3;
अब, मान लें कि एक व्यावसायिक आवश्यकता है जहां हम लगातार उन आदेशों की समीक्षा करना चाहते हैं जिनमें ऐसे उत्पाद हैं जिन्हें अभी तक एक ट्रैकिंग नंबर असाइन नहीं किया गया है (सोचें कि ऑर्डर विभाजित और अलग से भेजे गए हैं)। वर्तमान तालिका में हम इन प्रश्नों को चलाएंगे (और मैंने हर मामले में कोल्ड कैश सुनिश्चित करने के लिए DBCC कमांड जोड़े हैं):
DBCC DROPCLEANBUFFERS;DBCC FREEPROCCACHE; सेल्स से COUNT(*) चुनें। सेल्स से प्रोडक्ट आईडी, सेल्सऑर्डर आईडी चुनें।जिसके लिए क्लस्टर इंडेक्स स्कैन की आवश्यकता होती है और निम्नलिखित रनटाइम मेट्रिक्स प्राप्त करते हैं (जैसा कि SQL संतरी प्लान एक्सप्लोरर के साथ कैप्चर किया गया है):
"पुराने" दिनों में (अर्थात SQL सर्वर 2005 के बाद से), हमने यह अनुक्रमणिका बनाई होगी (और वास्तव में, SQL सर्वर 2012 में भी, यह वह अनुक्रमणिका है जो SQL सर्वर अनुशंसा करता है):
क्रिएट इंडेक्स IX_NotVeryHelpfulON [Sales].[SalesOrderDetailEnlarged] ([CarrierTrackingNumber])INCLUDE ([SalesOrderID],[ProductID]);उस अनुक्रमणिका के स्थान पर, और उपरोक्त प्रश्नों को फिर से चलाने के साथ, ये मीट्रिक हैं, दोनों क्वेरीज़ एक अनुक्रमणिका का उपयोग करते हुए आपकी अपेक्षा के अनुरूप हैं:
और फिर उस अनुक्रमणिका को छोड़कर थोड़ा अलग बनाना, बस एक
WHERE
. जोड़ना खंड:क्रिएट इंडेक्स IX_Filtered_CTNisNULLON [सेल्स]।हमें ये परिणाम मिलते हैं, और दोनों क्वेरीज़ अपनी खोज के लिए फ़िल्टर किए गए इंडेक्स का उपयोग करती हैं:
उपरोक्त प्रश्नों के रनटाइम और I/O में कमी की तुलना में प्रत्येक अनुक्रमणिका द्वारा आवश्यक अतिरिक्त स्थान यहां दिया गया है:
सूचकांक | इंडेक्स स्पेस | जोड़ा गया स्थान | <थ>अवधि <थ>पढ़ता है||
---|---|---|---|---|
कोई समर्पित अनुक्रमणिका नहीं | 363 एमबी | 15,700ms | ~164,000 | |
गैर-फ़िल्टर्ड अनुक्रमणिका | 530 एमबी | 167 एमबी (+46%) | 169ms | 1,084 |
फ़िल्टर की गई अनुक्रमणिका | 367 एमबी | 4 एमबी (+1%) | 170ms | 1,084 |
इसलिए, जैसा कि आप देख सकते हैं, फ़िल्टर्ड इंडेक्स प्रदर्शन में सुधार प्रदान करता है जो लगभग गैर-फ़िल्टर्ड इंडेक्स के समान होता है (चूंकि दोनों समान संख्या में रीड का उपयोग करके अपना डेटा प्राप्त करने में सक्षम होते हैं), लेकिन बहुत कम स्टोरेज पर लागत, क्योंकि फ़िल्टर किए गए अनुक्रमणिका को केवल उन पंक्तियों को संग्रहीत और बनाए रखना होता है जो फ़िल्टर विधेय से मेल खाती हैं।
अब, तालिका को उसकी मूल स्थिति में वापस लाते हैं:
अपडेट सेल्स.सेल्सऑर्डरडिटेलएनलार्जेड एसईटी कैरियरट्रैकिंगनंबर =न्यूल जहां कैरियरट्रैकिंगनंबर ='एक्स'; DROP INDEX IX_NotVeryHelpful ON Sales.SalesOrderDetailEnlarged;DROP INDEX IX_Filtered_CTNबिक्री पर नहीं है।SalesOrderDetailEnlarged;
टिम चैपमैन (@chapmandew) और मिशेल उफोर्ड (@sqlfool) ने अपने तरीके से फ़िल्टर किए गए इंडेक्स के प्रदर्शन लाभों को रेखांकित करते हुए एक शानदार काम किया है, और आपको उनकी पोस्ट भी देखनी चाहिए:
- मिशेल यूफोर्ड:फ़िल्टर किए गए इंडेक्स:आपको क्या जानना चाहिए
- टिम चैपमैन:द जॉयज़ ऑफ़ फ़िल्टर्ड इंडेक्स
साथ ही, एएनएसआई-संगत अद्वितीय बाधाएं (प्रकार)
मैंने सोचा कि मैं संक्षेप में एएनएसआई-अनुपालन अद्वितीय बाधाओं का भी उल्लेख करूंगा। SQL सर्वर 2005 में, हम इस तरह एक अद्वितीय बाधा उत्पन्न करेंगे:
CREATE TABLE dbo.Personnel( EmployeeID INT PRIMARY KEY, SSN CHAR(9) NULL, -- ... अन्य कॉलम ... CONSTRAINT UQ_SSN UNIQUE(SSN));
(हम एक बाधा के बजाय एक अद्वितीय गैर-संकुल सूचकांक भी बना सकते हैं; अंतर्निहित कार्यान्वयन अनिवार्य रूप से समान है।)
अब, यह कोई समस्या नहीं है यदि प्रवेश के समय एसएसएन ज्ञात हो:
INSERT dbo.Personnel(EmployeeID, SSN)VALUES(1,'111111111'),(2,'111111112');
यह भी ठीक है अगर हमारे पास कभी-कभी एसएसएन होता है जो प्रवेश के समय ज्ञात नहीं होता है (वीज़ा आवेदक या शायद यहां तक कि एक विदेशी कर्मचारी भी जिसके पास एसएसएन नहीं है और कभी नहीं होगा):
INSERT dbo.Personnel(EmployeeID, SSN)VALUES(3,NULL);
अब तक सब ठीक है. लेकिन क्या होता है जब हमारे पास सेकंड . होता है अज्ञात SSN वाला कर्मचारी?
INSERT dbo.Personnel(EmployeeID, SSN)VALUES(4,NULL);
परिणाम:
Msg 2627, Level 14, State 1, Line 1UNIQUE KEY बाधा 'UQ_SSN' का उल्लंघन। ऑब्जेक्ट 'dbo.Personnel' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लीकेट कुंजी मान (
विवरण समाप्त कर दिया गया है।
तो किसी भी समय, इस कॉलम में केवल एक NULL मान मौजूद हो सकता है। अधिकांश परिदृश्यों के विपरीत, यह एक ऐसा मामला है जहां SQL सर्वर दो NULL मानों को समान मानता है (यह निर्धारित करने के बजाय कि समानता केवल अज्ञात है और, बदले में, गलत है)। लोग वर्षों से इस विसंगति की शिकायत कर रहे हैं।
यदि यह एक आवश्यकता है, तो अब हम फ़िल्टर्ड इंडेक्स का उपयोग करके इस पर काम कर सकते हैं:
ALTER TABLE dbo.Personnel DROP CONSTRAINT UQ_SSN;GO UNIQUE INDEX UQ_SSN ON dbo.Personnel(SSN) जहां SSN न्यूल नहीं है;
अब हमारा चौथा इंसर्ट ठीक काम करता है, क्योंकि विशिष्टता केवल गैर-नल मानों पर लागू होती है। यह एक तरह का धोखा है, लेकिन यह उन बुनियादी आवश्यकताओं को पूरा करता है जो एएनएसआई मानक का इरादा है (भले ही SQL सर्वर हमें ALTER TABLE ... ADD CONSTRAINT
का उपयोग करने की अनुमति नहीं देता है। फ़िल्टर की गई अनूठी बाधा बनाने के लिए वाक्यविन्यास)।
लेकिन, फ़ोन को थामे रहें
फ़िल्टर किए गए इंडेक्स के साथ हम क्या कर सकते हैं, इसके ये बेहतरीन उदाहरण हैं, लेकिन बहुत सी चीजें हैं जो हम अभी भी नहीं कर सकते हैं, और इसके परिणामस्वरूप कई सीमाएं और समस्याएं सामने आती हैं।
आंकड़े अपडेट
यह IMHO की अधिक महत्वपूर्ण सीमाओं में से एक है। फ़िल्टर किए गए इंडेक्स को फ़िल्टर विधेय द्वारा पहचाने गए तालिका के सबसेट के प्रतिशत परिवर्तन के आधार पर आँकड़ों के ऑटो-अपडेट से लाभ नहीं होता है; यह पूरी तालिका के खिलाफ मंथन पर आधारित है (सभी गैर-फ़िल्टर्ड इंडेक्स की तरह)। इसका मतलब यह है कि, फ़िल्टर किए गए इंडेक्स में तालिका के कितने प्रतिशत के आधार पर, इंडेक्स में पंक्तियों की संख्या चौगुनी या आधी हो सकती है और आंकड़े तब तक अपडेट नहीं होंगे जब तक कि आप मैन्युअल रूप से ऐसा नहीं करते। किम्बर्ली ट्रिप ने इसके बारे में कुछ बेहतरीन जानकारी दी है (और गेल शॉ एक उदाहरण का हवाला देते हैं जहां केवल 10,000 पंक्तियों वाले फ़िल्टर किए गए इंडेक्स के लिए आंकड़ों को अपडेट करने से पहले 257,000 अपडेट लिए गए थे):
http://www.sqlskills.com/blogs/kimberly/filtered-indexes-and-filtered-stats-might-become-serious-out-of-date/
http://www.sqlskills.com/ ब्लॉग/किम्बर्ली/श्रेणी/फ़िल्टर किए गए इंडेक्स/
साथ ही, किम्बर्ली के सहयोगी, जो सैक (@JosephSack) ने एक कनेक्ट आइटम दायर किया है जो फ़िल्टर्ड इंडेक्स और फ़िल्टर किए गए आंकड़ों दोनों के लिए इस व्यवहार को ठीक करने का सुझाव देता है।
अभिव्यक्ति सीमा फ़िल्टर करें
ऐसी कई संरचनाएँ हैं जिनका उपयोग आप फ़िल्टर विधेय में नहीं कर सकते हैं, जैसे NOT IN
, OR
और डायनेमिक/गैर-नियतात्मक विधेय जैसे WHERE col >= DATEADD(DAY, -1, GETDATE())
. साथ ही, यदि विधेय WHERE
से सटीक रूप से मेल नहीं खाता है, तो अनुकूलक फ़िल्टर किए गए अनुक्रमणिका को नहीं पहचान सकता है सूचकांक परिभाषा में खंड। यहां कुछ कनेक्ट आइटम दिए गए हैं जो यहां बेहतर कवरेज के लिए कुछ समर्थन देने का प्रयास करते हैं:
फ़िल्टर की गई अनुक्रमणिका वियोजनों पर फ़िल्टर की अनुमति नहीं देती | (बंद:डिज़ाइन द्वारा) |
NOT IN क्लॉज के साथ फ़िल्टर की गई अनुक्रमणिका बनाना विफल | (बंद:डिज़ाइन द्वारा) |
फ़िल्टर किए गए अनुक्रमणिका में अधिक जटिल WHERE क्लॉज़ के लिए समर्थन | (सक्रिय) |
अन्य संभावित उपयोग वर्तमान में संभव नहीं हैं
हम वर्तमान में एक स्थिर गणना कॉलम पर फ़िल्टर्ड इंडेक्स नहीं बना सकते हैं, भले ही वह नियतात्मक हो। हम एक अद्वितीय फ़िल्टर्ड इंडेक्स पर एक विदेशी कुंजी को इंगित नहीं कर सकते हैं; यदि हम चाहते हैं कि कोई अनुक्रमणिका फ़िल्टर किए गए अनुक्रमणिका द्वारा समर्थित प्रश्नों के अतिरिक्त विदेशी कुंजी का समर्थन करे, तो हमें एक दूसरा, निरर्थक, गैर-फ़िल्टर्ड इंडेक्स बनाना होगा। और यहां कुछ अन्य समान सीमाएं हैं जिन्हें या तो अनदेखा कर दिया गया है या अभी तक उन पर विचार नहीं किया गया है:
एक नियतात्मक स्थायी परिकलित स्तंभ पर फ़िल्टर्ड अनुक्रमणिका बनाना संभव होना चाहिए | (सक्रिय) |
फ़िल्टर किए गए अद्वितीय इंडेक्स को विदेशी कुंजी के लिए उम्मीदवार कुंजी बनने दें | (सक्रिय) |
अनुक्रमित दृश्यों पर फ़िल्टर अनुक्रमणिका बनाने की क्षमता | (बंद:ठीक नहीं होगा) |
विभाजन त्रुटि 1908 - विभाजन को बेहतर बनाएं | (बंद:ठीक नहीं होगा) |
"फ़िल्टर किया गया" कॉलमस्टोर इंडेक्स बनाएं | (सक्रिय) |
मर्ज की समस्याएं
और MERGE
मेरी "वॉच आउट" सूची में एक और उपस्थिति दर्ज करता है:
MERGE प्रति पंक्ति फ़िल्टर किए गए अनुक्रमणिका का मूल्यांकन करता है, पोस्ट ऑपरेशन का नहीं, जो फ़िल्टर किए गए अनुक्रमणिका उल्लंघन का कारण बनता है | (बंद:ठीक नहीं होगा) |
MERGE फ़िल्टर किए गए इंडेक्स के साथ अपडेट करने में विफल रहता है | (बंद:निश्चित) |
मर्ज स्टेटमेंट बग जब INSERT/DELETE का उपयोग किया गया और इंडेक्स को फ़िल्टर किया गया | (सक्रिय) |
MERGE अद्वितीय कुंजी उल्लंघनों की गलत रिपोर्ट करता है | (सक्रिय) |
जबकि इनमें से एक (निकट रूप से संबंधित) बग का कहना है कि यह SQL सर्वर 2012 में तय किया गया है, आपको PSS से संपर्क करने की आवश्यकता हो सकती है यदि आप इस समस्या के किसी भी बदलाव को मार रहे हैं, विशेष रूप से पुराने संस्करणों पर (या MERGE का उपयोग करना बंद कर दें) , जैसा कि मैंने पहले सुझाव दिया है)।
उपकरण / DMV / अंतर्निहित सीमाएं
कई डीएमवी, डीबीसीसी कमांड, सिस्टम प्रक्रियाएं और क्लाइंट टूल्स हैं जिन पर हम समय के साथ भरोसा करना शुरू कर देते हैं। हालांकि, नई सुविधाओं का लाभ उठाने के लिए इन सभी चीजों को अपडेट नहीं किया जाता है; फ़िल्टर्ड इंडेक्स कोई अपवाद नहीं हैं। निम्नलिखित कनेक्ट आइटम कुछ मुद्दों की ओर इशारा करते हैं जो आपको परेशान कर सकते हैं यदि आप उनसे फ़िल्टर्ड इंडेक्स के साथ काम करने की उम्मीद कर रहे हैं:
नई तालिका डिज़ाइन करते समय SSMS से फ़िल्टर किए गए अनुक्रमणिका बनाने का कोई तरीका नहीं है | (बंद:ठीक नहीं होगा) |
टेबल डिज़ाइनर द्वारा तालिका को संशोधित करने पर फ़िल्टर किए गए इंडेक्स का फ़िल्टर एक्सप्रेशन खो जाता है | (बंद:ठीक नहीं होगा) |
टेबल डिज़ाइनर फ़िल्टर्ड इंडेक्स में WHERE क्लॉज़ को स्क्रिप्ट नहीं करता है | (सक्रिय) |
SSMS तालिका डिज़ाइनर तालिका पुनर्निर्माण पर अनुक्रमणिका फ़िल्टर व्यंजक को संरक्षित नहीं करता है | (बंद:ठीक नहीं होगा) |
DBCC PAGE फ़िल्टर किए गए इंडेक्स के साथ गलत आउटपुट | (सक्रिय) |
एसक्यूएल 2008 डीएम व्यूज और डीटीए से फ़िल्टर किए गए इंडेक्स सुझाव | (बंद:ठीक नहीं होगा) |
फ़िल्टर किए गए अनुक्रमणिका के लिए अनुपलब्ध अनुक्रमणिका DMV का संवर्द्धन | (बंद:ठीक नहीं होगा) |
संपीड़ित फ़िल्टर किए गए अनुक्रमणिका को दोहराते समय सिंटैक्स त्रुटि | (बंद:ठीक नहीं होगा) |
एजेंट:T-SQL स्क्रिप्ट चलाते समय नौकरियां गैर-डिफ़ॉल्ट विकल्पों का उपयोग करती हैं | (बंद:ठीक नहीं होगा) |
देखें निर्भरताएँ Transact-SQL त्रुटि 515 के साथ विफल हो जाती हैं | (सक्रिय) |
देखें निर्भरता कुछ वस्तुओं पर विफल हो जाती है | (बंद:ठीक नहीं होगा) |
दो डेटाबेस के लिए तुलना स्कीमा में इंडेक्स विकल्प अंतर का पता नहीं चला है | (बंद:बाहरी) |
सूचकांक जानकारी के सभी दृश्यों में सूचकांक फ़िल्टर स्थिति को उजागर करने का सुझाव दें | (बंद:ठीक नहीं होगा) |
sp_helpIndex परिणामों में फ़िल्टर इंडेक्स की फ़िल्टर अभिव्यक्ति शामिल होनी चाहिए | (सक्रिय) |
2008 सुविधाओं के लिए sp_help, sp_columns, sp_helpindex को अधिभारित करें | (बंद:ठीक नहीं होगा) |
आखिरी तीन के लिए, अपनी सांस रोककर न रखें - Microsoft द्वारा sp_ प्रक्रियाओं, DMVs, INFORMATION_SCHEMA विचारों आदि में किसी भी समय निवेश करने की संभावना नहीं है। इसके बजाय Kimberly Tripp का sp_helpindex पुनर्लेखन देखें, जिसमें फ़िल्टर किए गए अनुक्रमणिका के बारे में जानकारी शामिल है। अन्य नई सुविधाओं के साथ जिन्हें Microsoft ने पीछे छोड़ दिया है।
अनुकूलक सीमाएं
ऐसे कई कनेक्ट आइटम हैं जो उन मामलों का वर्णन करते हैं जहां फ़िल्टर किए गए अनुक्रमणिका * को अनुकूलक द्वारा उपयोग किया जा सकता है, लेकिन इसके बजाय उन्हें अनदेखा कर दिया जाता है। कुछ मामलों में इन्हें "बग" नहीं बल्कि "कार्यक्षमता में अंतराल" माना जाता है...
SQL साधारण क्वेरी पर फ़िल्टर किए गए अनुक्रमणिका का उपयोग नहीं करता | (बंद:डिज़ाइन द्वारा) |
फ़िल्टर की गई अनुक्रमणिका निष्पादन योजना अनुकूलित नहीं है | (बंद:ठीक नहीं होगा) |
फ़िल्टर किए गए अनुक्रमणिका का उपयोग नहीं किया गया और बिना आउटपुट के कुंजी लुकअप | (बंद:ठीक नहीं होगा) |
बीआईटी कॉलम पर फ़िल्टर्ड इंडेक्स का उपयोग WHERE क्लॉज में प्रयुक्त सटीक SQL अभिव्यक्ति पर निर्भर करता है | (सक्रिय) |
लिंक की गई सर्वर क्वेरी ठीक से अनुकूलित नहीं होती जब फ़िल्टर की गई अद्वितीय अनुक्रमणिका मौजूद होती है | (बंद:ठीक नहीं होगा) |
Row_Number() लिंक किए गए सर्वर पर अप्रत्याशित परिणाम देता है जहां फ़िल्टर किए गए इंडेक्स का उपयोग किया जाता है | (बंद:कोई रेप्रो नहीं) |
स्पष्ट फ़िल्टर इंडेक्स QP द्वारा उपयोग नहीं किया गया | (बंद:डिज़ाइन द्वारा) |
अद्वितीय फ़िल्टर किए गए अनुक्रमणिका को अद्वितीय के रूप में पहचानें | (सक्रिय) |
पॉल व्हाइट (@SQL_Kiwi) ने हाल ही में यहां SQLPerformance.com पर एक पोस्ट पोस्ट की है जिसमें ऊपर दी गई कुछ अनुकूलक सीमाओं के बारे में विस्तार से बताया गया है।
और टिम चैपमैन ने फ़िल्टर्ड इंडेक्स की कुछ अन्य सीमाओं को रेखांकित करते हुए एक बेहतरीन पोस्ट लिखी - जैसे कि स्थानीय चर (2008 R2 SP1 में तय) के लिए विधेय का मिलान करने में असमर्थता और एक इंडेक्स संकेत में फ़िल्टर किए गए इंडेक्स को निर्दिष्ट करने में असमर्थता।
निष्कर्ष
फ़िल्टर किए गए इंडेक्स में काफी संभावनाएं हैं और जब उन्हें पहली बार SQL Server 2008 में पेश किया गया था, तो मुझे उनसे बहुत अधिक उम्मीदें थीं। हालाँकि, उनके पहले संस्करण के साथ शिप की गई अधिकांश सीमाएँ आज भी मौजूद हैं, डेढ़ (या दो, आपके आधार पर) परिप्रेक्ष्य) प्रमुख रिलीज़ बाद में। उपरोक्त वस्तुओं की एक बहुत व्यापक कपड़े धोने की सूची की तरह लगता है जिसे संबोधित करने की आवश्यकता है, लेकिन मेरा मतलब यह नहीं था कि यह उस तरह से आ जाए। मैं बस इतना चाहता हूं कि लोग बड़ी संख्या में संभावित मुद्दों से अवगत हों, जिन पर उन्हें फ़िल्टर्ड इंडेक्स का लाभ उठाते समय विचार करने की आवश्यकता हो सकती है।