पिछले महीने मैंने एक कुशल संख्या श्रृंखला जनरेटर बनाने के लिए एक चुनौती पोस्ट की थी। प्रतिक्रियाएं जबरदस्त थीं। इस विशेष चुनौती से परे बहुत सारे अनुप्रयोगों के साथ कई शानदार विचार और सुझाव थे। इससे मुझे एहसास हुआ कि एक समुदाय का हिस्सा होना कितना अच्छा है, और यह आश्चर्यजनक चीजें हासिल की जा सकती हैं जब स्मार्ट लोगों का एक समूह सेना में शामिल हो जाता है। अपने विचारों और टिप्पणियों को साझा करने के लिए धन्यवाद एलन बर्स्टीन, जो ओबिश, एडम मचानिक, क्रिस्टोफर फोर्ड, जेफ मोडन, चार्ली, नोआमजीआर, कामिल कोस्नो, डेव मेसन और जॉन नंबर2।
प्रारंभ में मैंने लोगों द्वारा प्रस्तुत विचारों को संक्षेप में प्रस्तुत करने के लिए केवल एक लेख लिखने के बारे में सोचा, लेकिन बहुत अधिक थे। इसलिए मैं कवरेज को कई लेखों में विभाजित करूँगा। इस महीने मैं मुख्य रूप से चार्लीज और एलन बर्स्टीन के दो मूल समाधानों में सुझाए गए सुधारों पर ध्यान केंद्रित करूंगा, जिन्हें मैंने पिछले महीने dbo.GetNumsItzikBatch और dbo.GetNumsItzik नामक इनलाइन टीवीएफ के रूप में पोस्ट किया था। मैं बेहतर संस्करणों को क्रमशः dbo.GetNumsAlanCharlieItzikBatch और dbo.GetNumsAlanCharlieItzik नाम दूंगा।
यह बहुत रोमांचक है!
इत्ज़िक के मूल समाधान
एक त्वरित अनुस्मारक के रूप में, पिछले महीने मैंने जिन कार्यों को कवर किया था, वे एक आधार CTE का उपयोग करते हैं जो 16 पंक्तियों के साथ एक टेबल वैल्यू कंस्ट्रक्टर को परिभाषित करता है। फ़ंक्शंस कैस्केडिंग सीटीई की एक श्रृंखला का उपयोग करते हैं, प्रत्येक अपने पूर्ववर्ती सीटीई के दो उदाहरणों के उत्पाद (क्रॉस जॉइन) को लागू करते हैं। इस तरह, आधार एक से परे पांच सीटीई के साथ, आप 4,294,967,296 पंक्तियों का एक सेट प्राप्त कर सकते हैं। Nums नामक एक सीटीई 1 से शुरू होने वाली संख्याओं की एक श्रृंखला बनाने के लिए ROW_NUMBER फ़ंक्शन का उपयोग करता है। अंत में, बाहरी क्वेरी इनपुट @low और @high के बीच अनुरोधित श्रेणी में संख्याओं की गणना करती है।
dbo.GetNumsItzikBatch फ़ंक्शन बैच प्रोसेसिंग प्राप्त करने के लिए कॉलमस्टोर इंडेक्स वाली तालिका में डमी जॉइन का उपयोग करता है। यहाँ डमी टेबल बनाने के लिए कोड दिया गया है:
क्रिएट टेबल dbo.BatchMe(col1 INT NOT NULL, INDEX idx_cs CLUSTERED COLUMNSTORE);
और यहाँ dbo.GetNumsItzikBatch फ़ंक्शन को परिभाषित करने वाला कोड है:
क्रिएट या अल्टर फंक्शन dbo.GetNumsItzikBatch(@low AS BIGINT, @high AS BIGINT) L0 AS के साथ TABLEASRETURN लौटाता है (सेलेक्ट 1 AS c से (VALUES(1),(1),(1),(1),) (1),(1),(1),(1), (1),(1),(1),(1),(1),(1),(1),(1)) AS D (सी)), एल1 एएस (एक क्रॉस जॉइन एल0 एएस बी के रूप में एल0 से सी का चयन करें), एल2 एएस (एल 1 से एक क्रॉस जॉइन एल 1 एएस बी के रूप में चुनें), एल 3 एएस (एल 2 से 1 एएस सी चुनें) एक क्रॉस के रूप में एल 2 एएस बी के रूप में शामिल हों), संख्या के रूप में (सेलेक्ट ROW_NUMBER() ओवर (ऑर्डर बाय (सिलेक्ट न्यूल)) एल 3 से राउनम के रूप में) टॉप चुनें (@ हाई - @ लो + 1) @ लो + राउनम - 1 एएस एन से संख्या बाएं बाहरी शामिल हों dbo.BatchMe ON 1 =0 rownum द्वारा ऑर्डर करें;
मैंने SSMS में सक्षम "निष्पादन के बाद परिणाम छोड़ें" के साथ फ़ंक्शन का परीक्षण करने के लिए निम्न कोड का उपयोग किया:
dbo से चुनें।GetNumsItzikBatch(1, 100000000) विकल्प (MAXDOP 1);
यहाँ प्रदर्शन आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:
CPU समय =16985 ms, बीता हुआ समय =18348 ms.
Dbo.GetNumsItzik फ़ंक्शन समान है, केवल इसमें डमी जॉइन नहीं है, और सामान्य रूप से पूरी योजना में पंक्ति मोड प्रोसेसिंग प्राप्त करता है। यहाँ फ़ंक्शन की परिभाषा है:
क्रिएट या अल्टर फंक्शन dbo.GetNumsItzik(@low as BIGINT, @high as BIGINT) L0 AS के साथ TABLEASRETURN लौटाता है (सेलेक्ट 1 AS c से (VALUES(1),(1),(1),(1), (1),(1),(1),(1), (1),(1),(1),(1),(1),(1),(1),(1)) AS D (सी)), एल1 एएस (एक क्रॉस जॉइन एल0 एएस बी के रूप में एल0 से सी का चयन करें), एल2 एएस (एल 1 से एक क्रॉस जॉइन एल 1 एएस बी के रूप में चुनें), एल 3 एएस (एल 2 से 1 एएस सी चुनें) एक क्रॉस के रूप में एल 2 एएस बी के रूप में शामिल हों), संख्या के रूप में (सेलेक्ट ROW_NUMBER() ओवर (ऑर्डर बाय (सिलेक्ट न्यूल)) एल 3 से राउनम के रूप में) टॉप चुनें (@ हाई - @ लो + 1) @ लो + राउनम - 1 एएस एन से पंक्ति क्रम से क्रमांक;
यहाँ वह कोड है जिसका उपयोग मैंने फ़ंक्शन का परीक्षण करने के लिए किया था:
dbo से चुनें।GetNumsItzik(1, 100000000) विकल्प (MAXDOP 1);
यहाँ प्रदर्शन आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:
CPU समय =19969 ms, बीता हुआ समय =21229 ms.
एलन बर्स्टीन और चार्ली के सुधार
एलन और चार्ली ने मेरे कार्यों में कई सुधारों का सुझाव दिया, कुछ मध्यम प्रदर्शन प्रभाव के साथ और कुछ अधिक नाटकीय के साथ। मैं चार्ली के निष्कर्षों के साथ संकलन ओवरहेड और निरंतर तह के बारे में शुरू करूँगा। फिर मैं एलन के सुझावों को शामिल करूंगा, जिसमें 1-आधारित बनाम @ कम-आधारित अनुक्रम (चार्ली और जेफ मोडेन द्वारा साझा किए गए), अनावश्यक सॉर्ट से बचना, और विपरीत क्रम में संख्याओं की श्रेणी की गणना करना शामिल है।
संकलन समय निष्कर्ष
जैसा कि चार्ली ने उल्लेख किया है, एक संख्या श्रृंखला जनरेटर का उपयोग अक्सर बहुत कम संख्या में पंक्तियों के साथ श्रृंखला उत्पन्न करने के लिए किया जाता है। उन मामलों में, कोड का संकलन समय कुल क्वेरी प्रसंस्करण समय का एक बड़ा हिस्सा बन सकता है। आईटीवीएफ का उपयोग करते समय यह विशेष रूप से महत्वपूर्ण है, क्योंकि संग्रहीत प्रक्रियाओं के विपरीत, यह पैरामीटरयुक्त क्वेरी कोड नहीं है जो अनुकूलित हो जाता है, बल्कि पैरामीटर एम्बेडिंग के बाद क्वेरी कोड होता है। दूसरे शब्दों में, मापदंडों को अनुकूलन से पहले इनपुट मानों के साथ प्रतिस्थापित किया जाता है, और स्थिरांक वाले कोड को अनुकूलित किया जाता है। इस प्रक्रिया के नकारात्मक और सकारात्मक दोनों प्रभाव हो सकते हैं। नकारात्मक प्रभावों में से एक यह है कि आपको अधिक संकलन मिलते हैं क्योंकि फ़ंक्शन को विभिन्न इनपुट मानों के साथ बुलाया जाता है। इस कारण से, संकलन समय को निश्चित रूप से ध्यान में रखा जाना चाहिए-खासकर जब फ़ंक्शन का उपयोग छोटी श्रेणियों के साथ बहुत बार किया जाता है।
विभिन्न आधार सीटीई कार्डिनैलिटीज के लिए चार्ली को मिले संकलन समय यहां दिए गए हैं:
2:22ms4:9ms16:7ms256:35ms
यह देखने के लिए उत्सुक है कि इनमें से 16 इष्टतम है, और जब आप अगले स्तर तक जाते हैं, तो एक बहुत ही नाटकीय छलांग होती है, जो कि 256 है। याद रखें कि फ़ंक्शन dbo.GetNumsItzikBacth और dbo.GetNumsItzik 16 के आधार CTE कार्डिनैलिटी का उपयोग करते हैं। ।
लगातार तह करना
निरंतर तह अक्सर एक सकारात्मक निहितार्थ है कि सही परिस्थितियों में सक्षम किया जा सकता है धन्यवाद पैरामीटर एम्बेडिंग प्रक्रिया के लिए धन्यवाद जो एक iTVF अनुभव करता है। उदाहरण के लिए, मान लें कि आपके फ़ंक्शन में एक व्यंजक @x + 1 है, जहां @x फ़ंक्शन का एक इनपुट पैरामीटर है। आप इनपुट के रूप में @x =5 के साथ फ़ंक्शन का आह्वान करते हैं। इनलाइन एक्सप्रेशन तब 5 + 1 हो जाता है, और यदि निरंतर फोल्डिंग के लिए योग्य है (इस पर जल्द ही और अधिक), तो 6 हो जाता है। यदि यह एक्सप्रेशन कॉलम को शामिल करने वाले अधिक विस्तृत एक्सप्रेशन का हिस्सा है, और कई लाखों पंक्तियों पर लागू होता है, तो यह हो सकता है सीपीयू चक्रों में गैर-नगण्य बचत का परिणाम।
मुश्किल हिस्सा यह है कि SQL सर्वर निरंतर फोल्ड करने के लिए और निरंतर फोल्ड नहीं करने के बारे में बहुत पसंद करता है। उदाहरण के लिए, SQL सर्वर नहीं होगा लगातार फोल्ड col1 + 5 + 1, न ही यह 5 + col1 + 1 को फोल्ड करेगा। लेकिन यह 5 + 1 + col1 से 6 + col1 को फोल्ड करेगा। मुझे पता है। इसलिए, उदाहरण के लिए, यदि आपका फ़ंक्शन dbo.T1 से SELECT @x + col1 + 1 AS mycol1 लौटाता है, तो आप निम्न छोटे परिवर्तन के साथ निरंतर फोल्डिंग सक्षम कर सकते हैं:dbo.T1 से @x + 1 + col1 AS mycol1 चुनें। मेरा विश्वास मत करो? परफ़ॉर्मेंसV5 डेटाबेस (या आपके डेटा के साथ मिलते-जुलते सवाल) में निम्नलिखित तीन प्रश्नों के लिए योजनाओं की जाँच करें और स्वयं देखें:
dbo.orders से myorderid के रूप में ऑर्डर आईडी + 5 + 1 चुनें; dbo.orders से myorderid के रूप में 5 + ऑर्डरिड + 1 चुनें; dbo.orders से 5 + 1 + ऑर्डरिड AS myorderid चुनें;
मुझे इन तीन प्रश्नों के लिए कंप्यूट स्केलर ऑपरेटरों में क्रमशः निम्नलिखित तीन भाव मिले:
[Expr1003] =स्केलर ऑपरेटर ([PerformanceV5]। dbo].[आदेश]।देखें कि मैं इसके साथ कहाँ जा रहा हूँ? अपने कार्यों में मैंने परिणाम कॉलम n को परिभाषित करने के लिए निम्नलिखित अभिव्यक्ति का उपयोग किया:
@low + rownum - 1 AS nचार्ली ने महसूस किया कि निम्नलिखित छोटे बदलावों के साथ, वह निरंतर तह को सक्षम कर सकता है:
@low - 1 + rownum AS nउदाहरण के लिए, @low =1 के साथ dbo.GetNumsItzik के लिए मैंने जो पिछली क्वेरी प्रदान की थी, उसके लिए मूल रूप से कंप्यूट स्केलर ऑपरेटर द्वारा परिभाषित निम्नलिखित अभिव्यक्ति थी:
[Expr1154] =स्केलर ऑपरेटर((1)+[Expr1153]-(1))उपरोक्त मामूली परिवर्तन को लागू करने के बाद, योजना में अभिव्यक्ति बन जाती है:
[Expr1154] =स्केलर ऑपरेटर((0)+[Expr1153])यह शानदार है!
जहां तक प्रदर्शन प्रभाव का सवाल है, याद रखें कि परिवर्तन से पहले dbo.GetNumsItzikBatch के विरुद्ध क्वेरी के लिए मुझे जो प्रदर्शन आंकड़े मिले, वे निम्नलिखित थे:
CPU समय =16985 ms, बीता हुआ समय =18348 ms.बदलाव के बाद मुझे जो नंबर मिले, वे ये हैं:
CPU समय =16375 ms, बीता हुआ समय =17932 ms.यहाँ वे संख्याएँ हैं जो मुझे dbo.GetNumsItzik के विरुद्ध क्वेरी के लिए मूल रूप से मिली हैं:
CPU समय =19969 ms, बीता हुआ समय =21229 ms.और ये हैं बदलाव के बाद के नंबर:
CPU समय =19266 ms, बीता हुआ समय =20588 ms.प्रदर्शन में कुछ प्रतिशत का ही सुधार हुआ। लेकिन रुकिए, और भी बहुत कुछ है! यदि आपको ऑर्डर किए गए डेटा को संसाधित करने की आवश्यकता है, तो प्रदर्शन के निहितार्थ बहुत अधिक नाटकीय हो सकते हैं, जैसा कि मैं बाद में ऑर्डर करने के बारे में अनुभाग में प्राप्त करूंगा।
1-आधारित बनाम @निम्न-आधारित अनुक्रम और विपरीत पंक्ति संख्या
एलन, चार्ली और जेफ ने नोट किया कि वास्तविक जीवन के अधिकांश मामलों में जहां आपको संख्याओं की एक श्रृंखला की आवश्यकता होती है, आपको इसे 1 या कभी-कभी 0 से शुरू करने की आवश्यकता होती है। एक अलग प्रारंभिक बिंदु की आवश्यकता के लिए यह बहुत कम आम है। तो यह और अधिक समझ में आता है कि फ़ंक्शन हमेशा एक सीमा लौटाता है जो 1 से शुरू होता है, और जब आपको एक अलग प्रारंभिक बिंदु की आवश्यकता होती है, तो फ़ंक्शन के विरुद्ध क्वेरी में बाहरी रूप से किसी भी गणना को लागू करें।
एलन वास्तव में एक सुरुचिपूर्ण विचार के साथ आया था कि इनलाइन टीवीएफ दोनों एक कॉलम लौटाता है जो 1 से शुरू होता है (बस ROW_NUMBER फ़ंक्शन का सीधा परिणाम) जिसे आरएन के रूप में उपनामित किया जाता है, और एक कॉलम जो n के रूप में @low उपनाम से शुरू होता है। चूंकि फ़ंक्शन इनलाइन हो जाता है, जब बाहरी क्वेरी केवल कॉलम rn के साथ इंटरैक्ट करती है, तो कॉलम n का मूल्यांकन भी नहीं होता है, और आपको प्रदर्शन लाभ मिलता है। जब आपको @low से शुरू करने के लिए अनुक्रम की आवश्यकता होती है, तो आप कॉलम n के साथ बातचीत करते हैं और लागू अतिरिक्त लागत का भुगतान करते हैं, इसलिए कोई स्पष्ट बाहरी गणना जोड़ने की कोई आवश्यकता नहीं है। एलन ने ऑप नामक एक कॉलम जोड़ने का भी सुझाव दिया जो विपरीत क्रम में संख्याओं की गणना करता है, और इस तरह के अनुक्रम की आवश्यकता होने पर ही इसके साथ बातचीत करता है। कॉलम सेशन गणना पर आधारित है:@high + 1 - rownum। इस कॉलम का महत्व तब होता है जब आपको पंक्तियों को अवरोही क्रम में संसाधित करने की आवश्यकता होती है जैसा कि मैं बाद में क्रम अनुभाग में प्रदर्शित करता हूं।
तो, आइए चार्ली और एलन के सुधारों को मेरे कार्यों में लागू करें।
बैच मोड संस्करण के लिए, सुनिश्चित करें कि आप पहले कॉलमस्टोर इंडेक्स के साथ डमी टेबल बनाते हैं, अगर यह पहले से मौजूद नहीं है:
क्रिएट टेबल dbo.BatchMe(col1 INT NOT NULL, INDEX idx_cs CLUSTERED COLUMNSTORE);फिर dbo.GetNumsAlanCharlieItzikBatch फ़ंक्शन के लिए निम्न परिभाषा का उपयोग करें:
क्रिएट या अल्टर फंक्शन dbo.GetNumsAlanCharlieItzikBatch(@low AS BIGINT =1, @high AS BIGINT) L0 AS के साथ TABLEASRETURN लौटाता है (से 1 AS c चुनें (VALUES(1),(1),(1),(1) ),(1),(1),(1),(1), (1),(1),(1),(1),(1),(1),(1),(1)) एएस डी (सी)), एल 1 एएस (एक क्रॉस जॉइन एल 0 एएस बी के रूप में एल 0 से सी चुनें), एल 2 एएस (एल 1 से एक क्रॉस जॉइन एल 1 एएस बी के रूप में चुनें), एल 3 एएस (चुनें 1 एएस सी चुनें) L2 से एक क्रॉस जॉइन L2 AS B के रूप में), नंबर्स AS (सिलेक्ट ROW_NUMBER() ओवर (ऑर्डर बाय (सिलेक्ट NULL)) AS Rownum L3 से) सेलेक्ट टॉप (@high - @low + 1) rownum AS rn, @high + 1 - राउनम एएस ऑप, @लो - 1 + राउनम एएस एन फ्रॉम नंबर्स लेफ्ट आउटर जॉइन dbo.BatchMe ON 1 =0 Rownum द्वारा ऑर्डर करें;फ़ंक्शन का उपयोग करने के लिए यहां एक उदाहरण दिया गया है:
dbo से चुनें।यह कोड निम्न आउटपुट उत्पन्न करता है:
rn op n--------1 3 -22 2 -13 1 04 0 15 -1 26 -2 3इसके बाद, 100M पंक्तियों के साथ फ़ंक्शन के प्रदर्शन का परीक्षण करें, पहले कॉलम n लौटाएं:
dbo से चुनें.GetNumsAlanCharlieItzikBatch(1, 100000000) विकल्प (MAXDOP 1);इस निष्पादन के लिए मुझे जो प्रदर्शन आंकड़े मिले हैं, वे यहां दिए गए हैं:
CPU समय =16375 ms, बीता हुआ समय =17932 ms.जैसा कि आप देख सकते हैं, सीपीयू और बीता हुआ समय दोनों में dbo.GetNumsItzikBatch की तुलना में एक छोटा सा सुधार है, जो यहां लगातार फोल्डिंग के कारण हुआ है।
फ़ंक्शन का परीक्षण करें, केवल इस बार कॉलम rn लौटाते हैं:
dbo.GetNumsAlanCharlieItzikBatch(1, 100000000) OPTION(MAXDOP 1);इस निष्पादन के लिए मुझे जो प्रदर्शन आंकड़े मिले हैं, वे यहां दिए गए हैं:
CPU समय =15890 ms, बीता हुआ समय =18561 ms.सीपीयू का समय और कम हो गया, हालांकि लगता है कि बीता हुआ समय कॉलम n को क्वेरी करने की तुलना में इस निष्पादन में थोड़ा बढ़ गया है।
चित्र 1 में दोनों प्रश्नों की योजना है।
चित्र 1:GetNumsAlanCharlieItzikBatch n बनाम rn पर लौटने की योजना
आप योजनाओं में स्पष्ट रूप से देख सकते हैं कि कॉलम आरएन के साथ बातचीत करते समय, अतिरिक्त कंप्यूट स्केलर ऑपरेटर की कोई आवश्यकता नहीं है। पहली योजना में निरंतर फोल्डिंग गतिविधि के परिणाम पर भी ध्यान दें जिसका मैंने पहले वर्णन किया था, जहां @low – 1 + rownum को 1 – 1 + rownum में इनलाइन किया गया था, और फिर 0 + rownum में फोल्ड किया गया था।
dbo नामक फ़ंक्शन के पंक्ति-मोड संस्करण की परिभाषा यहां दी गई है। GetNumsAlanCharlieItzik:
क्रिएट या अल्टर फंक्शन dbo.GetNumsAlanCharlieItzik(@low AS BIGINT =1, @high AS BIGINT) L0 AS के साथ TABLEASRETURN लौटाता है (सेलेक्ट 1 AS c से (VALUES(1),(1),(1),(1) ),(1),(1),(1),(1), (1),(1),(1),(1),(1),(1),(1),(1)) एएस डी (सी)), एल 1 एएस (एक क्रॉस जॉइन एल 0 एएस बी के रूप में एल 0 से सी चुनें), एल 2 एएस (एल 1 से एक क्रॉस जॉइन एल 1 एएस बी के रूप में चुनें), एल 3 एएस (चुनें 1 एएस सी चुनें) L2 से एक क्रॉस जॉइन L2 AS B के रूप में), नंबर्स AS (सिलेक्ट ROW_NUMBER() ओवर (ऑर्डर बाय (सिलेक्ट NULL)) AS Rownum L3 से) सेलेक्ट टॉप (@high - @low + 1) rownum AS rn, @high + 1 - राउनम एएस ऑप, @लो - 1 + राउनम एएस एन फ्रॉम नंबर्स ऑर्डर बाय राउनम;फ़ंक्शन का परीक्षण करने के लिए निम्न कोड का उपयोग करें, पहले कॉलम n को क्वेरी करें:
dbo से चुनें।GetNumsAlanCharlieItzik(1, 100000000) विकल्प (MAXDOP 1);यहाँ प्रदर्शन आँकड़े हैं जो मुझे मिले:
CPU समय =19047 ms, बीता हुआ समय =20121 ms.जैसा कि आप देख सकते हैं, यह dbo.GetNumsItzik से थोड़ा तेज़ है।
इसके बाद, कॉलम rn को क्वेरी करें:
dbo से चयन करें। GetNumsAlanCharlieItzik(1, 100000000) विकल्प (MAXDOP 1);सीपीयू और बीता हुआ समय दोनों मोर्चों पर प्रदर्शन संख्या में और सुधार होता है:
CPU समय =17656 ms, बीता हुआ समय =18990 ms.आदेश देना विचार
उपरोक्त सुधार निश्चित रूप से दिलचस्प हैं, और प्रदर्शन प्रभाव नगण्य है, लेकिन बहुत महत्वपूर्ण नहीं है। जब आपको संख्या कॉलम द्वारा ऑर्डर किए गए डेटा को संसाधित करने की आवश्यकता होती है, तो बहुत अधिक नाटकीय और गहरा प्रदर्शन प्रभाव देखा जा सकता है। यह ऑर्डर की गई पंक्तियों को वापस करने की आवश्यकता जितना आसान हो सकता है, लेकिन किसी भी ऑर्डर-आधारित प्रसंस्करण आवश्यकता के लिए उतना ही प्रासंगिक है, उदाहरण के लिए, समूहीकरण और एकत्रीकरण के लिए एक स्ट्रीम एग्रीगेट ऑपरेटर, शामिल होने के लिए एक मर्ज जॉइन एल्गोरिदम, और आगे।पी>
dbo.GetNumsItzikBatch या dbo.GetNumsItzik को क्वेरी करते समय और n द्वारा ऑर्डर करते समय, ऑप्टिमाइज़र को यह नहीं पता होता है कि अंतर्निहित ऑर्डरिंग एक्सप्रेशन @low + rownum – 1 ऑर्डर-संरक्षण है। रोवनम के संबंध में। निहितार्थ एक गैर-SARGable फ़िल्टरिंग अभिव्यक्ति के समान है, केवल एक ऑर्डरिंग अभिव्यक्ति के साथ यह योजना में एक स्पष्ट सॉर्ट ऑपरेटर में परिणाम देता है। अतिरिक्त प्रकार प्रतिक्रिया समय को प्रभावित करता है। यह स्केलिंग को भी प्रभावित करता है, जो आमतौर पर n के बजाय n लॉग n बन जाता है।
इसे प्रदर्शित करने के लिए, क्वेरी dbo.GetNumsItzikBatch, कॉलम n का अनुरोध करते हुए, n द्वारा आदेशित:
nFROM dbo.GetNumsItzikBatch(1,100000000)NOPTION द्वारा ऑर्डर करें(MAXDOP 1);मुझे निम्नलिखित प्रदर्शन आँकड़े मिले:
CPU समय =34125 ms, बीता हुआ समय =39656 ms.ORDER BY क्लॉज के बिना परीक्षण की तुलना में रन टाइम दोगुने से अधिक है।
इसी तरह से dbo.GetNumsItzik फ़ंक्शन का परीक्षण करें:
nFROM dbo.GetNumsItzik(1,100000000)NOPTION द्वारा ऑर्डर करें(MAXDOP 1);मुझे इस परीक्षण के लिए निम्नलिखित नंबर मिले हैं:
CPU समय =52391 ms, बीता हुआ समय =55175 ms.साथ ही यहां ORDER BY क्लॉज के बिना टेस्ट की तुलना में रन टाइम दोगुने से भी ज्यादा है।
चित्र 2 में दोनों प्रश्नों की योजना है।
चित्र 2:n द्वारा GetNumsItzikBatch और GetNumsItzik ऑर्डर करने की योजना
दोनों ही मामलों में आप योजनाओं में स्पष्ट सॉर्ट ऑपरेटर देख सकते हैं।
dbo.GetNumsAlanCharlieItzikBatch या dbo.GetNumsAlanCharlieItzik को क्वेरी करते समय और rn द्वारा ऑर्डर करते समय ऑप्टिमाइज़र को योजना में सॉर्ट ऑपरेटर जोड़ने की आवश्यकता नहीं होती है। तो आप एन वापस कर सकते हैं, लेकिन आरएन द्वारा ऑर्डर करें, और इस तरह से एक प्रकार से बचें। क्या थोड़ा चौंकाने वाला है, हालांकि - और मेरा मतलब यह एक अच्छे तरीके से है - यह है कि n का संशोधित संस्करण जो निरंतर तह का अनुभव करता है, आदेश-संरक्षण है! ऑप्टिमाइज़र के लिए यह महसूस करना आसान है कि 0 + राउनम राउनम के संबंध में एक ऑर्डर-प्रिजर्विंग एक्सप्रेशन है, और इस प्रकार एक प्रकार से बचा जाता है।
इसे अजमाएं। क्वेरी dbo.GetNumsAlanCharlieItzikBatch, रिटर्निंग n, और n या rn द्वारा ऑर्डर करना, जैसे:
dbo से nFROM चुनें।मुझे निम्नलिखित प्रदर्शन संख्याएँ मिलीं:
CPU समय =16500 ms, बीता हुआ समय =17684 ms.यह निश्चित रूप से इस तथ्य के लिए धन्यवाद है कि योजना में सॉर्ट ऑपरेटर की कोई आवश्यकता नहीं थी।
dbo.GetNumsAlanCharlieItzik के विरुद्ध एक समान परीक्षण चलाएँ:
dbo से nFROM चुनें।मुझे निम्नलिखित नंबर मिले:
CPU समय =19546 ms, बीता हुआ समय =20803 ms.चित्र 3 में दोनों प्रश्नों की योजना है:
चित्र 3:GetNumsAlanCharlieItzikBatch और GetNumsAlanCharlieItzik के लिए n या rn द्वारा ऑर्डर करने की योजनाध्यान दें कि योजनाओं में कोई सॉर्ट ऑपरेटर नहीं है।
क्या आप गाना चाहते हैं...
आपको केवल निरंतर फोल्डिंग की आवश्यकता है, आपको केवल निरंतर फोल्डिंग की आवश्यकता है, आपको केवल निरंतर फोल्डिंग की आवश्यकता है, निरंतर फोल्डिंग लगातार फोल्डिंग की आपको आवश्यकता हैधन्यवाद चार्ली!
लेकिन क्या होगा यदि आपको संख्याओं को अवरोही क्रम में वापस करने या संसाधित करने की आवश्यकता है? स्पष्ट प्रयास ORDER BY n DESC, या ORDER BY rn DESC का उपयोग करना है, जैसे:
nFROM dbo.GetNumsAlanCharlieItzikBatch(1,100000000) से n DESCOPTION (MAXDOP 1) का चयन करें; nFROM dbo.GetNumsAlanCharlieItzikBatch(1,100000000) RN DESCOPTION (MAXDOP 1) द्वारा आदेश चुनें;दुर्भाग्य से, हालांकि, दोनों मामलों में योजनाओं में एक स्पष्ट प्रकार का परिणाम होता है, जैसा कि चित्र 4 में दिखाया गया है।
चित्र 4:GetNumsAlanCharlieItzikBatch के लिए n या rn अवरोही क्रम में योजनाएँ
यहीं पर कॉलम सेशन के साथ एलन की चतुर चाल जीवन रक्षक बन जाती है। n या rn द्वारा ऑर्डर करते समय कॉलम ऑप लौटाएं, जैसे:
dbo से चयन करें।इस क्वेरी की योजना चित्र 5 में दिखाई गई है।
चित्र 5:GetNumsAlanCharlieItzikBatch के लिए योजना n या rn आरोही द्वारा ऑप और ऑर्डर लौटाना उन्हें>
आपको n अवरोही क्रम में डेटा वापस मिलता है और योजना में किसी प्रकार की कोई आवश्यकता नहीं है।
धन्यवाद एलन!
प्रदर्शन सारांश
तो इन सब से हमने क्या सीखा?
संकलन समय एक कारक हो सकता है, विशेष रूप से छोटी श्रेणियों के साथ अक्सर फ़ंक्शन का उपयोग करते समय। आधार 2 के साथ लघुगणकीय पैमाने पर, मिठाई 16 एक अच्छी जादुई संख्या लगती है।
निरंतर तह की ख़ासियत को समझें और अपने लाभ के लिए उनका उपयोग करें। जब किसी iTVF में ऐसे व्यंजक हों जिनमें पैरामीटर, स्थिरांक और स्तंभ शामिल हों, तो पैरामीटर और स्थिरांक को व्यंजक के प्रमुख भाग में रखें। इससे फोल्डिंग की संभावना बढ़ जाएगी, CPU ओवरहेड कम हो जाएगा और ऑर्डर संरक्षण की संभावना बढ़ जाएगी।
आईटीवीएफ में अलग-अलग उद्देश्यों के लिए उपयोग किए जाने वाले कई कॉलम होना ठीक है, और प्रत्येक मामले में संबंधित लोगों को संदर्भित नहीं किए गए लोगों के भुगतान के बारे में चिंता किए बिना पूछताछ करना ठीक है।
जब आपको विपरीत क्रम में दिए गए नंबर अनुक्रम की आवश्यकता होती है, तो आरोही क्रम के साथ ORDER BY क्लॉज में मूल n या rn कॉलम का उपयोग करें, और कॉलम op को वापस करें, जो संख्याओं की गणना व्युत्क्रम क्रम में करता है।
चित्र 6 विभिन्न परीक्षणों में मुझे मिले प्रदर्शन संख्याओं का सारांश देता है।
चित्र 6:प्रदर्शन सारांश
अगले महीने मैं संख्या श्रृंखला जनरेटर चुनौती के लिए अतिरिक्त विचार, अंतर्दृष्टि और समाधान तलाशना जारी रखूंगा।