मुझे गलत मत समझो - मुझे वास्तविक पंक्तियाँ पढ़ना पसंद है जो हमने SQL सर्वर की निष्पादन योजनाओं में देखी है। 2015 के अंत में। लेकिन SQL सर्वर 2016 SP1 में, दो महीने से भी कम समय पहले (और यह देखते हुए कि हमारे बीच क्रिसमस है, मुझे नहीं लगता कि तब से ज्यादा समय मायने रखता है), हमें एक और रोमांचक जोड़ मिला - पढ़ी जाने वाली पंक्तियों की अनुमानित संख्या (ओह, और यह मेरे द्वारा सबमिट किए गए कनेक्ट आइटम के लिए कुछ हद तक नीचे है, दोनों यह प्रदर्शित करते हैं कि कनेक्ट आइटम सबमिट करने योग्य हैं और इस पोस्ट को इस महीने के टी-एसक्यूएल मंगलवार के लिए योग्य बनाते हैं, जिसे ब्रेंट ओज़र (@ ब्रेंटो) द्वारा कनेक्ट आइटम के विषय पर होस्ट किया गया है। )।
आइए एक पल का पुनरावलोकन करें ... जब SQL इंजन किसी तालिका में डेटा एक्सेस करता है, तो यह स्कैन ऑपरेशन या सीक ऑपरेशन का उपयोग करता है। और जब तक कि सीक के पास सीक प्रेडिकेट नहीं है जो अधिकतम एक पंक्ति तक पहुंच सकता है (क्योंकि यह कॉलम के एक सेट पर एक समानता मैच की तलाश में है - केवल एक कॉलम हो सकता है - जिसे अद्वितीय माना जाता है), तब सीक एक प्रदर्शन करेगा रेंजस्कैन, और सीक प्रेडिकेट द्वारा संतुष्ट पंक्तियों के सबसेट में बिल्कुल स्कैन की तरह व्यवहार करता है।
सीक प्रेडिकेट (सीक ऑपरेशन के रेंजस्कैन के मामले में) या तालिका की सभी पंक्तियों (स्कैन ऑपरेशन के मामले में) से संतुष्ट पंक्तियों को अनिवार्य रूप से उसी तरह माना जाता है। यदि ऑपरेटर से बाईं ओर कोई और पंक्तियों का अनुरोध नहीं किया जाता है, तो दोनों को जल्दी समाप्त किया जा सकता है, उदाहरण के लिए यदि किसी शीर्ष ऑपरेटर ने पहले से ही पर्याप्त पंक्तियों को पकड़ लिया है, या यदि मर्ज ऑपरेटर के पास मिलान करने के लिए कोई और पंक्तियाँ नहीं हैं। और दोनों को एक अवशिष्ट विधेय ('विधेय' संपत्ति के रूप में दिखाया गया है) द्वारा आगे फ़िल्टर किया जा सकता है, इससे पहले कि स्कैन/सीक ऑपरेटर द्वारा पंक्तियों को भी सेवा दी जाए। "पंक्तियों की संख्या" और "पंक्तियों की अनुमानित संख्या" गुण हमें बताएंगे कि ऑपरेटर द्वारा कितनी पंक्तियों का उत्पादन करने की उम्मीद थी, लेकिन हमें इस बारे में कोई जानकारी नहीं थी कि केवल सीक प्रेडिकेट द्वारा पंक्तियों को कैसे फ़िल्टर किया जाएगा। हम टेबलकार्डिनैलिटी देख सकते थे, लेकिन यह केवल स्कैन ऑपरेटरों के लिए वास्तव में उपयोगी था, जहां एक मौका था कि स्कैन पूरी तालिका को उन पंक्तियों के लिए देख सकता है जिनकी उसे आवश्यकता थी। यह सीक्स के लिए बिल्कुल भी उपयोगी नहीं था।
मैं यहां जो क्वेरी चला रहा हूं वह वाइडवर्ल्डइम्पोर्टर्स डेटाबेस के खिलाफ है, और यह है:
बिक्री से COUNT(*) चुनें। ऑर्डर जहां सेल्सपर्सनआईडी =7 और साल (ऑर्डरडेट) =2013और महीना (ऑर्डरडेट) =4;
इसके अलावा, मेरे पास खेलने में एक अनुक्रमणिका है:
नॉनक्लस्टर्ड इंडेक्स बनाएं rf_Orders_SalesPeople_OrderDate on Sales.Orders (SalespersonID, OrderDate);
यह इंडेक्स कवर कर रहा है - क्वेरी को अपना उत्तर पाने के लिए किसी अन्य कॉलम की आवश्यकता नहीं है - और इसे डिज़ाइन किया गया है ताकि सेल्सपर्सन आईडी पर सीक प्रेडिकेट का उपयोग किया जा सके, डेटा को जल्दी से एक छोटी सीमा तक फ़िल्टर कर सके। ऑर्डरडेट पर फ़ंक्शंस का मतलब है कि उन अंतिम दो विधेय का उपयोग सीक प्रेडिकेट के भीतर नहीं किया जा सकता है, इसलिए उन्हें इसके बजाय अवशिष्ट विधेय में ले जाया जाता है। एक बेहतर क्वेरी ऑर्डरडेट>='20130401' और ऑर्डरडेट <'20130501' का उपयोग करके उन तारीखों को फ़िल्टर करेगी, लेकिन मैं यहां एक ऐसे परिदृश्य की कल्पना कर रहा हूं जो बहुत आम है...
अब, यदि मैं क्वेरी चलाता हूं, तो मैं अवशिष्ट विधेय का प्रभाव देख सकता हूं। प्लान एक्सप्लोरर वह उपयोगी चेतावनी भी देता है जिसके बारे में मैंने पहले लिखा था।
मैं बहुत स्पष्ट रूप से देख सकता हूं कि रेंजस्कैन 7,276 पंक्तियाँ हैं, और यह कि अवशिष्ट विधेय इसे 149 तक फ़िल्टर करता है। प्लान एक्सप्लोरर टूलटिप पर इसके बारे में अधिक जानकारी दिखाता है:
लेकिन क्वेरी चलाए बिना, मैं वह जानकारी नहीं देख सकता। यह बस वहाँ नहीं है। अनुमानित योजना की संपत्तियों में यह नहीं है:
और मुझे यकीन है कि मुझे आपको याद दिलाने की आवश्यकता नहीं है - यह जानकारी प्लान कैश में भी मौजूद नहीं है। कैश से योजना को हथियाने के बाद:
चुनें p.query_plan, t.textFROM sys.dm_exec_cached_plans cCROSS APPLY sys.dm_exec_query_plan(c.plan_handle) pCROSS APPLY sys.dm_exec_sql_text(c.plan_handle) tWHERE 't.text LIKE';मैंने इसे खोल दिया, और निश्चित रूप से, उस 7,276 मूल्य का कोई संकेत नहीं है। यह बिल्कुल वैसा ही दिखता है, जैसा मैंने अभी-अभी दिखाया अनुमानित योजना है।
कैश से योजनाएं प्राप्त करना वह जगह है जहां अनुमानित मूल्य अपने आप आते हैं। ऐसा नहीं है कि मैं वास्तव में ग्राहक डेटाबेस पर संभावित-महंगी क्वेरी नहीं चलाना पसंद करूंगा। प्लान कैश को क्वेरी करना एक बात है, लेकिन वास्तविक जानकारी प्राप्त करने के लिए क्वेरी चलाना - यह बहुत कठिन है।
SQL 2016 SP1 स्थापित होने के साथ, उस कनेक्ट आइटम के लिए धन्यवाद, अब मैं अनुमानित योजनाओं में और योजना कैश में पढ़ी जाने वाली पंक्तियों की अनुमानित संख्या देख सकता हूं। यहां दिखाया गया ऑपरेटर टूलटिप कैश से लिया गया है, और मैं आसानी से देख सकता हूं कि अनुमानित संपत्ति 7,276 दिखा रही है, साथ ही अवशिष्ट चेतावनी:
यह कुछ ऐसा है जो मैं एक ग्राहक बॉक्स पर कर सकता था, समस्याग्रस्त योजनाओं में स्थितियों के लिए कैश में देख रहा था, जहां पंक्तियों की अनुमानित संख्या को पढ़ा जाना और पंक्तियों की अनुमानित संख्या का अनुपात बहुत अच्छा नहीं है। संभावित रूप से, कोई ऐसी प्रक्रिया बना सकता है जो कैश में हर योजना की जाँच करे, लेकिन यह ऐसा कुछ नहीं है जो मैंने किया है।
एस्ट्यूट रीडिंग ने देखा होगा कि इस ऑपरेटर से निकलने वाली वास्तविक पंक्तियाँ 149 थी, जो अनुमानित 1382.56 से बहुत छोटी थी। लेकिन जब मैं अवशिष्ट विधेय की तलाश कर रहा हूं जिसमें बहुत अधिक पंक्तियों की जांच करनी है, तो 1,382.56:7,276 का अनुपात अभी भी महत्वपूर्ण है।
अब जब हमने पाया है कि यह क्वेरी इसे चलाने की आवश्यकता के बिना भी अप्रभावी है, तो इसे ठीक करने का तरीका यह सुनिश्चित करना है कि अवशिष्ट विधेय पर्याप्त रूप से SARGable है। यह प्रश्न…
बिक्री से COUNT(*) चुनें। ऑर्डर जहां सेल्सपर्सनआईडी =7 और ऑर्डरडेट>='20130401' और ऑर्डरडेट <'20130501';...समान परिणाम देता है, और कोई अवशिष्ट विधेय नहीं है। इस स्थिति में, पढ़ी जाने वाली पंक्तियों की अनुमानित संख्या पंक्तियों की अनुमानित संख्या के समान होती है, और अक्षमता समाप्त हो जाती है:
जैसा कि पहले उल्लेख किया गया है, यह पोस्ट इस महीने के टी-एसक्यूएल मंगलवार का हिस्सा है। यह देखने के लिए वहां क्यों न जाएं कि हाल ही में कौन से अन्य फीचर अनुरोध दिए गए हैं?