Database
 sql >> डेटाबेस >  >> RDS >> Database

संख्या श्रृंखला जनरेटर चुनौती समाधान - भाग 2

संख्या श्रृंखला जनरेटर चुनौती के समाधान के बारे में श्रृंखला में यह दूसरा भाग है। पिछले महीने मैंने उन समाधानों को कवर किया जो स्थिरांक के आधार पर पंक्तियों के साथ टेबल वैल्यू कंस्ट्रक्टर का उपयोग करके मक्खी पर पंक्तियों को उत्पन्न करते हैं। उन समाधानों में कोई I/O संचालन शामिल नहीं था। इस महीने मैं उन समाधानों पर ध्यान केंद्रित करता हूं जो एक भौतिक आधार तालिका को क्वेरी करते हैं जिसे आप पंक्तियों के साथ पूर्व-पॉप्युलेट करते हैं। इस कारण से, मैंने पिछले महीने की तरह समाधानों की समय प्रोफ़ाइल की रिपोर्ट करने से परे, मैं नए समाधानों के I/O प्रोफ़ाइल की भी रिपोर्ट करूंगा। अपने विचारों और टिप्पणियों को साझा करने के लिए एलन बर्स्टीन, जो ओबिश, एडम मचानिक, क्रिस्टोफर फोर्ड, जेफ मोडन, चार्ली, नोआमजीआर, कामिल कोस्नो, डेव मेसन, जॉन नेल्सन #2 और एड वैगनर को फिर से धन्यवाद।

अब तक का सबसे तेज़ समाधान

सबसे पहले, एक त्वरित अनुस्मारक के रूप में, आइए पिछले महीने के लेख से सबसे तेज़ समाधान की समीक्षा करें, जिसे dbo.GetNumsAlanCharlieItzikBatch नामक इनलाइन TVF के रूप में लागू किया गया है।

मैं अपना परीक्षण tempdb में करूँगा, जिससे IO और TIME आँकड़े सक्षम होंगे:

नोकाउंट चालू करें; टेम्पर्ड का उपयोग करें; सांख्यिकी IO, समय चालू करें;

पिछले महीने से सबसे तेज़ समाधान एक डमी टेबल के साथ जुड़ने पर लागू होता है जिसमें बैच प्रोसेसिंग प्राप्त करने के लिए कॉलमस्टोर इंडेक्स होता है। यहाँ डमी टेबल बनाने के लिए कोड दिया गया है:

ड्रॉप टेबल अगर मौजूद है dbo.BatchMe;GO CREATE TABLE 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 द्वारा ऑर्डर करें;GO

पिछले महीने मैंने 100M पंक्तियों के साथ फ़ंक्शन के प्रदर्शन का परीक्षण करने के लिए निम्न कोड का उपयोग किया, आउटपुट पंक्तियों को वापस करने के लिए SSMS में निष्पादन के बाद परिणामों को त्यागने को सक्षम करने के बाद:

dbo से चुनें.GetNumsAlanCharlieItzikBatch(1, 100000000) विकल्प (MAXDOP 1);

यहाँ समय के आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:

सीपीयू समय =16031 एमएस, बीता हुआ समय =17172 एमएस।

जो ओबिश ने सही ढंग से नोट किया कि इस परीक्षण में कुछ वास्तविक जीवन परिदृश्यों के प्रतिबिंब में कमी हो सकती है, इस अर्थ में कि रन टाइम का एक बड़ा हिस्सा एसिंक नेटवर्क I/O प्रतीक्षा (ASYNC_NETWORK_IO प्रतीक्षा प्रकार) के कारण है। आप वास्तविक क्वेरी योजना के रूट नोड के गुण पृष्ठ को देखकर उच्चतम प्रतीक्षा देख सकते हैं, या प्रतीक्षा जानकारी के साथ एक विस्तारित ईवेंट सत्र चला सकते हैं। तथ्य यह है कि आप SSMS में निष्पादन के बाद परिणाम छोड़ें सक्षम करते हैं, SQL सर्वर को SSMS को परिणाम पंक्तियाँ भेजने से नहीं रोकता है; यह सिर्फ SSMS को उन्हें प्रिंट करने से रोकता है। सवाल यह है कि जब आप बड़ी संख्या में श्रृंखला बनाने के लिए फ़ंक्शन का उपयोग करते हैं, तब भी आप वास्तविक जीवन परिदृश्यों में क्लाइंट को बड़े परिणाम सेट वापस करने की कितनी संभावना है? शायद अधिक बार आप एक तालिका में क्वेरी परिणाम लिखते हैं, या फ़ंक्शन के परिणाम का उपयोग किसी क्वेरी के भाग के रूप में करते हैं जो अंततः एक छोटा परिणाम सेट उत्पन्न करता है। आपको यह पता लगाने की जरूरत है। आप SELECT INTO स्टेटमेंट का उपयोग करके परिणाम सेट को एक अस्थायी तालिका में लिख सकते हैं, या, आप एलन बर्स्टीन की चाल का उपयोग असाइनमेंट सेलेक्ट स्टेटमेंट के साथ कर सकते हैं, जो एक वैरिएबल को परिणाम कॉलम मान निर्दिष्ट करता है।

यहां बताया गया है कि आप वेरिएबल असाइनमेंट विकल्प का उपयोग करने के लिए अंतिम परीक्षण को कैसे बदलेंगे:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। GetNumsAlanCharlieItzikBatch(1, 100000000) विकल्प (MAXDOP 1);

यहाँ समय के आँकड़े हैं जो मुझे इस परीक्षा के लिए मिले हैं:

सीपीयू समय =8641 एमएस, बीता हुआ समय =8645 एमएस।

इस बार प्रतीक्षा जानकारी में कोई async नेटवर्क I/O प्रतीक्षा नहीं है, और आप रन टाइम में महत्वपूर्ण गिरावट देख सकते हैं।

फंक्शन को फिर से टेस्ट करें, इस बार ऑर्डरिंग जोड़ते हुए:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। 

मुझे इस निष्पादन के लिए निम्नलिखित प्रदर्शन आँकड़े मिले:

CPU समय =9360 ms, बीता हुआ समय =9551 ms.

याद रखें कि इस क्वेरी के लिए योजना में सॉर्ट ऑपरेटर की कोई आवश्यकता नहीं है क्योंकि कॉलम n एक अभिव्यक्ति पर आधारित है जो कॉलम राउनम के संबंध में संरक्षित क्रम है। यह चार्ली की निरंतर तह चाल के लिए धन्यवाद है, जिसे मैंने पिछले महीने कवर किया था। दोनों प्रश्नों के लिए योजनाएँ—बिना आदेश वाला और आदेश देने वाला एक ही हैं, इसलिए प्रदर्शन समान होता है।

चित्र 1 पिछले महीने के समाधानों के लिए मुझे मिले प्रदर्शन संख्याओं का सारांश देता है, केवल इस बार निष्पादन के बाद परिणामों को छोड़ने के बजाय परीक्षणों में चर असाइनमेंट का उपयोग करना।

चित्र 1:वेरिएबल असाइनमेंट के साथ अब तक का प्रदर्शन सारांश

मैं इस आलेख में प्रस्तुत किए जाने वाले शेष समाधानों का परीक्षण करने के लिए परिवर्तनीय असाइनमेंट तकनीक का उपयोग करूंगा। सुनिश्चित करें कि आप परिवर्तनशील असाइनमेंट, SELECT INTO, निष्पादन के बाद परिणाम या किसी अन्य तकनीक का उपयोग करके अपनी वास्तविक जीवन की स्थिति को सर्वोत्तम रूप से दर्शाने के लिए अपने परीक्षणों को समायोजित करते हैं।

बिना MAXDOP 1 के सीरियल प्लान ज़बरदस्ती करने के लिए युक्ति

इससे पहले कि मैं नए समाधान प्रस्तुत करूं, मैं सिर्फ एक छोटी सी युक्ति को कवर करना चाहता था। याद रखें कि सीरियल प्लान का उपयोग करते समय कुछ समाधान सर्वश्रेष्ठ प्रदर्शन करते हैं। इसे बाध्य करने का स्पष्ट तरीका MAXDOP 1 क्वेरी संकेत के साथ है। और यह सही तरीका है यदि आप कभी-कभी समानता को सक्षम करना चाहते हैं और कभी-कभी नहीं। हालांकि, क्या होगा यदि आप फ़ंक्शन का उपयोग करते समय हमेशा एक सीरियल प्लान को लागू करना चाहते हैं, भले ही इसकी संभावना कम हो?

इसे हासिल करने की एक तरकीब है। क्वेरी में नॉनलाइनेबल स्केलर UDF का उपयोग समानांतरवाद अवरोधक है। स्केलर यूडीएफ इनलाइनिंग इनहिबिटर में से एक एक आंतरिक कार्य को लागू कर रहा है जो समय पर निर्भर है, जैसे कि SYSDATETIME। तो यहां एक गैर-रेखीय अदिश UDF के लिए एक उदाहरण दिया गया है:

बनाएं या फंक्शन बदलें dbo.MySYSDATETIME() रिटर्न DATETIME2ASBEGIN रिटर्न SYSDATETIME();END;GO

एक अन्य विकल्प यूडीएफ को लौटाए गए मूल्य के रूप में केवल कुछ स्थिरांक के साथ परिभाषित करना है, और इसके शीर्षलेख में INLINE =OFF विकल्प का उपयोग करना है। लेकिन यह विकल्प केवल SQL सर्वर 2019 के साथ उपलब्ध है, जिसने स्केलर UDF इनलाइनिंग की शुरुआत की। उपरोक्त सुझाए गए फ़ंक्शन के साथ, आप इसे SQL सर्वर के पुराने संस्करणों के साथ बना सकते हैं।

इसके बाद, dbo की परिभाषा बदलें।

 क्रिएट या अल्टर फंक्शन 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, dbo.MySYSDATETIME() AS dontinline F From L3 ) सेलेक्ट टॉप(@high - @low + 1 ) Rownum AS rn, @high + 1 - rownum AS op, @low - 1 + rownum AS n से nums LEFT OUTER JOIN dbo.BatchMe ON 1 =0 Rownum द्वारा ऑर्डर करें;GO

अब आप MAXDOP 1 को निर्दिष्ट किए बिना प्रदर्शन परीक्षण फिर से चला सकते हैं और फिर भी एक सीरियल प्लान प्राप्त कर सकते हैं:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। 

हालांकि यह जोर देना महत्वपूर्ण है कि इस फ़ंक्शन का उपयोग करने वाले किसी भी प्रश्न को अब एक सीरियल प्लान मिलेगा। यदि कोई संभावना है कि फ़ंक्शन का उपयोग उन प्रश्नों में किया जाएगा जो समानांतर योजनाओं से लाभान्वित होंगे, तो बेहतर होगा कि इस ट्रिक का उपयोग न करें, और जब आपको एक सीरियल प्लान की आवश्यकता हो, तो बस MAXDOP 1 का उपयोग करें।

जो ओबिश द्वारा समाधान

जो का समाधान बहुत रचनात्मक है। यहाँ समाधान का उनका अपना विवरण है:

"मैंने अनुक्रमिक पूर्णांकों की 134,217,728 पंक्तियों के साथ एक क्लस्टर्ड कॉलमस्टोर इंडेक्स (सीसीआई) बनाने का विकल्प चुना है। परिणाम सेट के लिए आवश्यक सभी पंक्तियों को प्राप्त करने के लिए फ़ंक्शन तालिका को 32 बार तक संदर्भित करता है। मैंने एक सीसीआई चुना क्योंकि डेटा अच्छी तरह से संपीड़ित होगा (प्रति पंक्ति 3 बाइट से कम), आपको बैच मोड "मुफ्त में" मिलता है, और पिछले अनुभव से पता चलता है कि सीसीआई से अनुक्रमिक संख्याओं को पढ़ना किसी अन्य विधि के माध्यम से उन्हें उत्पन्न करने से तेज़ होगा। "

जैसा कि पहले उल्लेख किया गया है, जो ने यह भी नोट किया कि एसएसएमएस को पंक्तियों को प्रेषित करके उत्पन्न एसिंक नेटवर्क I/O प्रतीक्षा के कारण मेरा मूल प्रदर्शन परीक्षण काफी खराब था। इसलिए सभी परीक्षण जो मैं यहां करूंगा, वे चर असाइनमेंट के साथ एलन के विचार का उपयोग करेंगे। जो आपकी वास्तविक जीवन की स्थिति को सबसे करीब से दर्शाता है, उसके आधार पर अपने परीक्षणों को समायोजित करना सुनिश्चित करें।

जो कोड तालिका dbo.GetNumsObbishTable बनाने और इसे 134,217,728 पंक्तियों के साथ पॉप्युलेट करने के लिए उपयोग किया गया कोड है:

ड्रॉप टेबल अगर मौजूद है dbo.GetNumsObbishTable; क्रिएट टेबल dbo.GetNumsObbishTable (ID BIGINT NOT NULL, INDEX CCI CCLUSTERED COLUMNSTORE); GO SET NOCOUNT ON; DECLARE @c INT =0; जबकि @c <128BEGIN dbo में डालें। 1); SET @c =@c + 1;END;GO

मेरी मशीन पर इस कोड को पूरा करने में 1:04 मिनट का समय लगा।

आप निम्न कोड चलाकर इस तालिका के स्थान उपयोग की जांच कर सकते हैं:

EXEC sys.sp_spaceused @objname =N'dbo.GetNumsObbishTable';

मुझे लगभग 350 एमबी स्पेस का इस्तेमाल हुआ। अन्य समाधानों की तुलना में जो मैं इस लेख में प्रस्तुत करूंगा, यह काफी अधिक स्थान का उपयोग करता है।
SQL सर्वर के कॉलमस्टोर आर्किटेक्चर में, एक पंक्ति समूह 2^20 =1,048,576 पंक्तियों तक सीमित है। आप निम्न कोड का उपयोग करके देख सकते हैं कि इस तालिका के लिए कितने पंक्ति समूह बनाए गए थे:

 sys.column_store_row_groups से numrowgroups के रूप में COUNT(*) चुनें, जहां object_id =OBJECT_ID('dbo.GetNumsObbishTable');

मुझे 128 पंक्ति समूह मिले हैं।

यहाँ dbo.GetNumsObbish फ़ंक्शन की परिभाषा के साथ कोड दिया गया है:

dbo.GetNumsObbish(@low as BIGINT, @high as BIGINT)
CREATE या ALTER FUNCTION dbo.GetNumsObbish(@low as BIGINT, @high as BIGINT) रिटर्न्स TABLEASRETURN dbo से n के रूप में @low + ID का चयन करें। GetNumsObbishTable जहां आईडी <=@high - @low UNION ALL SELECT @low + ID + CAST (134217728 AS BIGINT) AS n FROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST (134217728 AS BIGINT) और ID <=@high - @low - CAST (134217728 AS BIGINT) यूनियन सभी चयन @ कम + आईडी + कास्ट (268435456 बिगिनट के रूप में) डीबीओ से। गेटनम्सऑबिशटेबल जहां @high - @low + 1> कास्ट (268435456 के रूप में बिगिनट) और आईडी <=@high - @low - कास्ट (268435456 के रूप में BIGINT) यूनियन सभी चयन @ कम + आईडी + कास्ट (402653184 बिगिनट के रूप में) डीबीओ से। गेटनम्सऑबिशटेबल जहां @high - @low + 1> कास्ट (402653184 बिगिनट के रूप में) और आईडी <=@ उच्च - @ कम - कास्ट (402653184 बिगिनट के रूप में) यूनियन सभी चयन @ लो + आईडी + कास्ट (536870912 बिगिनट के रूप में) डीबीओ से एन. @लो + आईडी + कास्ट (671088640 AS BIGINT) AS n F ROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(671088640 AS BIGINT) और ID <=@high - @low - CAST(671088640 AS BIGINT) यूनियन सभी चयन @low + ID + CAST(805306368 AS BIGINT) AS n dbo.GetNumsObbishTable से जहां @high - @low + 1> CAST(805306368 AS BIGINT) और ID <=@high - @low - CAST(805306368 AS BIGINT) UNION ALL SELECT @low + ID + CAST(939524096 AS BIGINT) dbo से n के रूप में। ) dbo से n के रूप में। BIGINT) dbo.GetNumsObbishTable से जहां @high - @low + 1> CAST(1207959552 AS BIGINT) और ID <=@high - @low - CAST(1207959552 AS BIGINT) UNION ALL SELECT @low + ID + CAST(1342177280) बिगिन के रूप में) dbo.GetNumsObbishTable से जहां @high - @l ow + 1> CAST (1342177280 AS BIGINT) और ID <=@high - @low - CAST (1342177280 AS BIGINT) यूनियन सभी चयन @ Low + ID + CAST (1476395008 AS BIGINT) AS n FROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(1476395008 AS BIGINT) और ID <=@high - @low - CAST(1476395008 AS BIGINT) यूनियन सभी चयन @ Low + ID + CAST (1610612736 AS BIGINT) AS n से dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(1610612736 AS BIGINT) और ID <=@high - @low - CAST(1610612736 AS BIGINT) यूनियन सभी चयन @low + ID + CAST(1744830464 AS BIGINT) AS n से dbo.GetNumsObbishTable WHERE @ High - @low + 1> CAST(1744830464 AS BIGINT) और ID <=@high - @low - CAST(1744830464 AS BIGINT) UNION ALL SELECT @low + ID + CAST(1879048192 AS BIGINT) AS n FROM dbo.GetNumsObbishTable WHERE @high - @low + 1> CAST(1879048192 AS BIGINT) और ID <=@high - @low - CAST(1879048192 AS BIGINT) यूनियन ऑल सिलेक्ट @low + ID + CAST (2013265920 AS BIGINT) AS n FROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(2013265920 AS BIGINT) और आईडी <=@high - @low - CAST(2013265920 AS BIGINT) यूनियन सभी चयन @low + ID + CAST (2147483648 AS BIGINT) n से dbo.GetNumsObbishTable जहां @high - @low + 1> CAST (2147483648 AS BIGINT) ) और आईडी <=@high - @low - CAST (2147483648 AS BIGINT) यूनियन सभी चयन @ कम + आईडी + कास्ट (2281701376 बिगिनट के रूप में) dbo से n के रूप में। GetNumsObbishTable जहां @ उच्च - @ कम + 1> कास्ट (22817701376 एएस) BIGINT) और ID <=@high - @low - CAST(2281701376 AS BIGINT) यूनियन सभी चयन @low + ID + CAST(2415919104 AS BIGINT) n से dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(2415919104) AS BIGINT) और ID <=@high - @low - CAST(2415919104 AS BIGINT) यूनियन सभी चयन @low + ID + CAST(2550136832 AS BIGINT) AS n से dbo.GetNumsObbishTable जहां @high - @low + 1> CAST( 2550136832 AS BIGINT) और ID <=@high - @low - CAST(2550136832 AS BIGINT) यूनियन ऑल सिलेक्ट @low + ID + CAST (2684354560 AS BIGINT) AS n FROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST (2684354560 AS BIGINT) और आईडी <=@high - @low - CAST(2684 354560 बिगिनट के रूप में) यूनियन सभी चयन @ कम + आईडी + कास्ट (2818572288 बिगिनट के रूप में) डीबीओ से एन। (2818572288 बिगिनट के रूप में) यूनियन ऑल सिलेक्ट @लो + आईडी + कास्ट (2952790016 बिगिन्ट के रूप में) डीबीओ से एन. कास्ट(2952790016 बिगिनट के रूप में) यूनियन ऑल सिलेक्ट @लो + आईडी + कास्ट (3087007744 बिगिन्ट के रूप में) डीबीओ से एन. - कास्ट (3087007744 बिगिनट के रूप में) यूनियन सभी चयन @ कम + आईडी + कास्ट (3221225472 बिगिनट के रूप में) डीबीओ से एन। कम - कास्ट (3221225472 बिगिनट के रूप में) यूनियन सभी चयन @ कम + आईडी + कास्ट (3355443200 बिगिन के रूप में) डीबीओ से एन के रूप में। GetNumsObbishTable जहां @ उच्च - @ कम + 1> कास्ट (3355443200 बिगिन के रूप में) और आईडी <=@ उच्च - @लो - कास्ट (3355443200 बिगिन के रूप में) यूनियन सभी का चयन करें @low + ID + CAST (3489660928 AS BIGINT) AS n FROM dbo.GetNumsObbishTable जहां @high - @low + 1> CAST(3489660928 AS BIGINT) और ID <=@high - @low - CAST(3489660928 AS BIGINT) यूनियन सभी dbo.GetNumsObbishTable जहां @high - @low + 1> CAST (3623878656 AS BIGINT) और ID <=@high - @low - CAST (3623878656 AS BIGINT) यूनियन से @low + ID + CAST (3623878656 AS BIGINT) चुनें। सभी चयन @ कम + आईडी + कास्ट (3758096384 बिगिनट के रूप में) डीबीओ से एन। GetNumsObbishTable जहां @ उच्च - @ कम + 1> कास्ट (3758096384 बिगिनट के रूप में) और आईडी <=@ उच्च - @ कम - कास्ट (3758096384 बिगिनट के रूप में) यूनियन सभी चयन @ कम + आईडी + कास्ट (3892314112 बिगिनट के रूप में) डीबीओ से एन। GetNumsObbishTable जहां @ उच्च - @ कम + 1> कास्ट (3892314112 बिगिनट के रूप में) और आईडी <=@ उच्च - @ कम - कास्ट (3892314112 बिगिनट के रूप में) ) यूनियन सभी चयन @ कम + आईडी + कास्ट (4026531840 बिगिन के रूप में) डीबीओ से एन। गेटनम्सऑबिशटेबल जहां @ उच्च - @ कम + 1> कास्ट (4026531840 बिगिनट के रूप में) और आईडी <=@ उच्च - @ कम - कास्ट (4026531840 एएस) बिगिनट) यूनियन ऑल सिलेक्ट @low + ID + CAST(4160749568 AS BIGI NT) dbo.GetNumsObbishTable से जहां @high - @low + 1> CAST(4160749568 AS BIGINT) और ID <=@high - @low - CAST(4160749568 AS BIGINT);GO

32 अलग-अलग प्रश्न 134,217,728-पूर्णांक उपश्रेणियों को उत्पन्न करते हैं, जो एकीकृत होने पर, 4,294,967,296 के माध्यम से पूर्ण निर्बाध श्रेणी 1 का उत्पादन करते हैं। इस समाधान के बारे में वास्तव में स्मार्ट क्या है जहां फ़िल्टर भविष्यवाणी करता है कि अलग-अलग प्रश्न उपयोग करते हैं। याद रखें कि जब SQL सर्वर इनलाइन TVF को संसाधित करता है, तो यह पहले पैरामीटर एम्बेडिंग को लागू करता है, पैरामीटर को इनपुट स्थिरांक के साथ प्रतिस्थापित करता है। SQL सर्वर तब उन प्रश्नों को ऑप्टिमाइज़ कर सकता है जो सबरेंज उत्पन्न करते हैं जो इनपुट रेंज के साथ प्रतिच्छेद नहीं करते हैं। उदाहरण के लिए, जब आप इनपुट रेंज 1 से 100,000,000 का अनुरोध करते हैं, तो केवल पहली क्वेरी प्रासंगिक होती है, और बाकी सभी अनुकूलित हो जाते हैं। इस मामले में योजना में तालिका के केवल एक उदाहरण का संदर्भ शामिल होगा। यह बहुत शानदार है!
आइए 1 से 100,000,000 की सीमा के साथ फ़ंक्शन के प्रदर्शन का परीक्षण करें:

घोषित @n के रूप में BIGINT; dbo.GetNumsObbish(1, 100000000) से @n =n चुनें;

इस क्वेरी की योजना चित्र 2 में दिखाई गई है।

चित्र 2:dbo के लिए योजना। GetNumsObbish, 100M पंक्तियाँ, क्रमरहित

ध्यान दें कि वास्तव में इस योजना में तालिका के CCI के केवल एक संदर्भ की आवश्यकता है।
मुझे इस निष्पादन के लिए निम्नलिखित समय के आँकड़े मिले हैं:

CPU समय =4969 ms, बीता हुआ समय =4982 ms.

यह बहुत प्रभावशाली है, और मेरे द्वारा परीक्षण की गई किसी भी चीज़ की तुलना में कहीं अधिक तेज़ है।

यहाँ I/O आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:

तालिका 'GetNumsObbishTable'। स्कैन काउंट 1, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड 0, लॉब लॉजिकल रीड्स 32928 , लॉब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड-आगे रीड्स 0, लोब पेज सर्वर रीड-फॉरवर्ड 0 पढ़ता है।

तालिका 'GetNumsObbishTable'। सेगमेंट 96 पढ़ता है , खंड 32 छोड़ दिया।

इस समाधान का I/O प्रोफ़ाइल दूसरों की तुलना में इसकी कमियों में से एक है, इस निष्पादन के लिए 30K से अधिक लॉज लॉजिकल रीड्स खर्च होते हैं।

यह देखने के लिए कि जब आप कई 134,217,728-पूर्णांक उपश्रेणियों को पार करते हैं, तो योजना में तालिका के कई संदर्भ शामिल होंगे, उदाहरण के लिए 1 से 400,000,000 की सीमा के साथ फ़ंक्शन को क्वेरी करें:

घोषित @n के रूप में BIGINT; dbo.GetNumsObbish(1, 400000000) से @n =n चुनें;

इस निष्पादन की योजना चित्र 3 में दिखाई गई है।

चित्र 3:dbo के लिए योजना। GetNumsObbish, 400M पंक्तियाँ, क्रमरहित

अनुरोधित सीमा तीन 134,217,728-पूर्णांक उपश्रेणियों को पार कर गई है, इसलिए योजना तालिका के CCI के तीन संदर्भ दिखाती है।

यहाँ समय के आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:

सीपीयू समय =20610 एमएस, बीता हुआ समय =20628 एमएस।

और यहाँ इसके I/O आँकड़े हैं:

तालिका 'GetNumsObbishTable'। स्कैन काउंट 3, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 131026 , लॉब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड-आगे रीड्स 0, लोब पेज सर्वर रीड-फॉरवर्ड 0 पढ़ता है।

तालिका 'GetNumsObbishTable'। सेगमेंट 382 पढ़ता है , खंड 2 छोड़ दिया गया।

इस बार क्वेरी निष्पादन के परिणामस्वरूप 130K से अधिक लॉज लॉजिकल रीड हुए।

यदि आप I/O लागतों को कम कर सकते हैं, और क्रमित तरीके से संख्या श्रृंखला को संसाधित करने की आवश्यकता नहीं है, तो यह एक बढ़िया समाधान है। हालाँकि, यदि आपको श्रृंखला को क्रम में संसाधित करने की आवश्यकता है, तो इस समाधान के परिणामस्वरूप योजना में एक सॉर्ट ऑपरेटर होगा। आदेशित परिणाम का अनुरोध करने वाला एक परीक्षण यहां दिया गया है:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। GetNumsObbish(1, 100000000) n द्वारा ऑर्डर करें;

इस निष्पादन की योजना चित्र 4 में दिखाई गई है।

चित्र 4:dbo के लिए योजना। GetNumsObbish, 100M पंक्तियाँ, आदेशित

यहाँ समय के आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:

सीपीयू समय =44516 एमएस, बीता हुआ समय =34836 एमएस।

जैसा कि आप देख सकते हैं, स्पष्ट छँटाई के कारण परिमाण के क्रम से चलने के समय में वृद्धि के साथ प्रदर्शन में काफी गिरावट आई है।

यहाँ I/O आँकड़े हैं जो मुझे इस निष्पादन के लिए मिले हैं:

तालिका 'GetNumsObbishTable'। स्कैन काउंट 4, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड 0, लॉब लॉजिकल रीड्स 32928 , लॉब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड-आगे रीड्स 0, लोब पेज सर्वर रीड-फॉरवर्ड 0 पढ़ता है।

तालिका 'GetNumsObbishTable'। सेगमेंट 96 पढ़ता है , खंड 32 छोड़ दिया गया।

टेबल 'वर्कटेबल'। स्कैन काउंट 0, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड्स 0, लोब लॉजिकल रीड्स 0, लोब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड- आगे 0 पढ़ता है, लोब पृष्ठ सर्वर आगे पढ़ता है 0 पढ़ता है।

ध्यान दें कि सांख्यिकी IO के आउटपुट में एक वर्कटेबल दिखाई देता है। ऐसा इसलिए है क्योंकि एक प्रकार संभावित रूप से tempdb तक फैल सकता है, इस मामले में यह एक वर्कटेबल का उपयोग करेगा। यह निष्पादन फैल नहीं गया, इसलिए इस प्रविष्टि में सभी संख्याएँ शून्य हैं।

जॉन नेल्सन #2, डेव, जो, एलन, चार्ली, इट्ज़िक द्वारा समाधान

जॉन नेल्सन #2 ने एक समाधान पोस्ट किया जो अपनी सादगी में बस सुंदर है। साथ ही, इसमें डेव, जो, एलन, चार्ली और स्वयं के अन्य समाधानों के विचार और सुझाव शामिल हैं।

जो के समाधान की तरह, जॉन ने उच्च स्तर की संपीड़न और "मुक्त" बैच प्रसंस्करण प्राप्त करने के लिए एक सीसीआई का उपयोग करने का निर्णय लिया। केवल जॉन ने तालिका को 4B पंक्तियों के साथ कुछ डमी NULL मार्कर के साथ एक बिट कॉलम में भरने का निर्णय लिया, और ROW_NUMBER फ़ंक्शन से संख्याएँ उत्पन्न कीं। चूंकि संग्रहीत मान सभी समान हैं, दोहराए जाने वाले मानों के संपीड़न के साथ आपको काफी कम स्थान की आवश्यकता होती है, जिसके परिणामस्वरूप जो के समाधान की तुलना में काफी कम I/Os होता है। कॉलमस्टोर कंप्रेशन दोहराव वाले मानों को बहुत अच्छी तरह से संभालता है क्योंकि यह लगातार दोहराए जाने वाली घटनाओं की गिनती के साथ-साथ एक पंक्ति समूह के कॉलम सेगमेंट के भीतर प्रत्येक ऐसे लगातार सेक्शन का प्रतिनिधित्व कर सकता है। चूंकि सभी पंक्तियों का एक ही मान (NULL मार्कर) होता है, सैद्धांतिक रूप से आपको प्रति पंक्ति समूह में केवल एक घटना की आवश्यकता होती है। 4B पंक्तियों के साथ, आपको 4,096 पंक्ति समूहों के साथ समाप्त होना चाहिए। प्रत्येक में एक एकल स्तंभ खंड होना चाहिए, जिसमें बहुत कम स्थान उपयोग की आवश्यकता हो।

यहाँ तालिका बनाने और भरने के लिए कोड है, जिसे अभिलेखीय संपीड़न के साथ CCI के रूप में लागू किया गया है:

 ड्रॉप टेबल अगर मौजूद है dbo.NullBits4B; टेबल डीबीओ बनाएं। 1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1) ,(1),(1),(1)) एएस डी(बी)), एल1 एएस (एल0 से एबी को क्रॉस जॉइन एल0 एएस बी के रूप में चुनें), एल2 एएस (एल1 से ए क्रॉस जॉइन एल1 एएस बी चुनें) ), नल (बी) एएस (एक क्रॉस के रूप में एल 2 से एबी चुनें एल 2 एएस बी में शामिल हों) डीबीओ में डालें। (टैबलॉक) के साथ नलबिट्स 4 बी (बी) नल से बी चुनें; जाओ

इस समाधान का मुख्य पहलू इस तालिका को भरने में लगने वाला समय है। समांतरता की अनुमति देते समय मेरी मशीन पर पूरा करने के लिए इस कोड को 12:32 मिनट और सीरियल योजना को मजबूर करते समय 15:17 मिनट लगे।

ध्यान दें कि आप डेटा लोड को अनुकूलित करने पर काम कर सकते हैं। उदाहरण के लिए, जॉन ने एक समाधान का परीक्षण किया जिसने OSTRESS.EXE के साथ 32 एक साथ कनेक्शन का उपयोग करके पंक्तियों को लोड किया, प्रत्येक में 2^20 पंक्तियों (अधिकतम पंक्ति समूह आकार) के सम्मिलन के 128 राउंड चल रहे थे। इस समाधान ने जॉन के लोड समय को एक तिहाई तक गिरा दिया। यहां जॉन द्वारा इस्तेमाल किया गया कोड है:

ओस्ट्रेस -एस (स्थानीय) \ YourSQLInstance -E -dtempdb -n32 -r128 -Q" L0 AS के साथ (सेलेक्ट कास्ट (नल के रूप में बिट) AS b से (VALUES(1),(1),(1),(1) ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS डी (बी)), एल 1 एएस (एल 0 से ए बी को क्रॉस जॉइन एल 0 एएस बी के रूप में चुनें), एल 2 एएस (एल 1 से ए बी को क्रॉस जॉइन एल 1 एएस बी के रूप में चुनें), नल (बी) एएस (एल 2 एएस ए से एबी चुनें) क्रॉस जॉइन L2 AS B) INSERT INTO dbo.NullBits4B(b) सेलेक्ट टॉप (1048576) b फ्रॉम नल ऑप्शन (MAXDOP 1);"

फिर भी, लोड समय मिनटों में है। अच्छी खबर यह है कि आपको यह डेटा लोड केवल एक बार करने की आवश्यकता है।

बड़ी खबर यह है कि तालिका के लिए आवश्यक छोटी मात्रा में स्थान है। स्थान के उपयोग की जांच के लिए निम्नलिखित कोड का प्रयोग करें:

EXEC sys.sp_spaceused @objname =N'dbo.NullBits4B';

मुझे 1.64 एमबी मिली। इस तथ्य को ध्यान में रखते हुए यह आश्चर्यजनक है कि तालिका में 4B पंक्तियाँ हैं!
निम्न कोड का उपयोग करके देखें कि कितने पंक्ति समूह बनाए गए थे:

sys.column_store_row_groups से numrowgroups के रूप में COUNT(*) चुनें, जहां object_id =OBJECT_ID('dbo.NullBits4B');

जैसी अपेक्षित थी, पंक्ति समूहों की संख्या 4,096 है।

dbo.GetNumsJohn2DaveObbishAlanCharlieItzik फ़ंक्शन परिभाषा तब बहुत सरल हो जाती है:

 क्रिएट या अल्टर फंक्शन dbo.GetNumsJohn2DaveObbishAlanCharlieItzik (@low AS BIGINT =1, @high AS BIGINT) रिटर्न टेबल्स रिटर्न्स विद नंबर्स एएस (सेलेक्ट ROW_NUMBER () ओवर (ऑर्डर बाय (सेलेक्ट न्यूल)) dbo. TOP(@high - @low + 1) rownum AS rn, @high + 1 - rownum AS op, @low - 1 + rownum AS n FROM नंबर्स BY rownum;GO

जैसा कि आप देख सकते हैं, तालिका के विरुद्ध एक साधारण क्वेरी आधार पंक्ति संख्या (राउनम कॉलम) की गणना करने के लिए ROW_NUMBER फ़ंक्शन का उपयोग करती है, और फिर बाहरी क्वेरी dbo के समान अभिव्यक्तियों का उपयोग करती है। rn, op और n की गणना करने के लिए GetNumsAlanCharlieItzikBatch। यहाँ भी, rn और n दोनों पंक्तिबद्ध क्रम के संबंध में संरक्षित हैं।
आइए फ़ंक्शन के प्रदर्शन का परीक्षण करें:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। GetNumsJohn2DaveObbishAlanCharlieItzik(1, 100000000);

मुझे इस निष्पादन के लिए चित्र 5 में दिखाया गया प्लान मिला है।

चित्र 5:dbo के लिए योजना।GetNumsJohn2DaveObbishAlanCharlieItzik

यहाँ समय के आँकड़े हैं जो मुझे इस परीक्षा के लिए मिले हैं:

सीपीयू समय =7593 एमएस, बीता हुआ समय =7590 एमएस।

जैसा कि आप देख सकते हैं, जो के समाधान के साथ निष्पादन का समय उतना तेज़ नहीं है, लेकिन यह अभी भी मेरे द्वारा परीक्षण किए गए अन्य सभी समाधानों की तुलना में तेज़ है।
यहां I/O आँकड़े दिए गए हैं जो मुझे इस परीक्षण के लिए मिले हैं: तालिका 'NullBits4B'। स्कैन काउंट 1, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड 0, लॉब लॉजिकल रीड्स 194 , लॉब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड-आगे रीड्स 0, लोब पेज सर्वर रीड-फॉरवर्ड 0 पढ़ता है।

तालिका 'NullBits4B'। सेगमेंट 96 पढ़ता है , खंड छोड़ दिया 0

ध्यान दें कि I/O आवश्यकताएं जो के समाधान की तुलना में काफी कम हैं।
इस समाधान के बारे में दूसरी बड़ी बात यह है कि जब आपको ऑर्डर की गई संख्या श्रृंखला को संसाधित करने की आवश्यकता होती है, तो आप कोई अतिरिक्त भुगतान नहीं करते हैं। ऐसा इसलिए है क्योंकि इससे योजना में स्पष्ट सॉर्ट ऑपरेशन नहीं होगा, भले ही आप परिणाम को rn या n के आधार पर ऑर्डर करें।
इसे प्रदर्शित करने के लिए यहां एक परीक्षण दिया गया है:

घोषित @n के रूप में BIGINT; dbo से @n =n चुनें। 

आपको वही प्लान मिलता है जो पहले चित्र 5 में दिखाया गया है।

यहाँ समय के आँकड़े हैं जो मुझे इस परीक्षा के लिए मिले;

सीपीयू समय =7578 एमएस, बीता हुआ समय =7582 एमएस।

और ये रहे I/O आँकड़े:

तालिका 'NullBits4B'। स्कैन काउंट 1, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, पेज सर्वर रीड्स 0, रीड-फॉरवर्ड रीड्स 0, पेज सर्वर रीड-फॉरवर्ड रीड 0, लॉब लॉजिकल रीड्स 194 , लॉब फिजिकल रीड्स 0, लोब पेज सर्वर रीड्स 0, लोब रीड-आगे रीड्स 0, लोब पेज सर्वर रीड-फॉरवर्ड 0 पढ़ता है।

तालिका 'NullBits4B'। सेगमेंट 96 पढ़ता है , खंड 0 छोड़ दिया।

वे मूल रूप से बिना आदेश के परीक्षण के समान हैं।

जॉन नेल्सन द्वारा समाधान 2 #2, डेव मेसन, जो ओबिश, एलन, चार्ली, इट्ज़िक

जॉन का समाधान तेज़ और सरल है। यह बढ़िया है। एक नकारात्मक पक्ष लोड समय है। कभी-कभी यह कोई समस्या नहीं होगी क्योंकि लोडिंग केवल एक बार होती है। लेकिन अगर यह एक समस्या है, तो आप तालिका को 4B पंक्तियों के बजाय 102,400 पंक्तियों के साथ पॉप्युलेट कर सकते हैं, और तालिका के दो उदाहरणों के बीच क्रॉस जॉइन का उपयोग कर सकते हैं और वांछित अधिकतम 4B पंक्तियों को उत्पन्न करने के लिए एक टॉप फ़िल्टर का उपयोग कर सकते हैं। ध्यान दें कि 4बी पंक्तियों को प्राप्त करने के लिए 65,536 पंक्तियों के साथ तालिका को पॉप्युलेट करना और फिर एक क्रॉस जॉइन लागू करना पर्याप्त होगा; हालांकि, डेटा को तुरंत संपीड़ित करने के लिए - जैसा कि एक पंक्ति-आधारित डेल्टा स्टोर में लोड होने के विपरीत है - आपको तालिका को न्यूनतम 102,400 पंक्तियों के साथ लोड करने की आवश्यकता है।

यहाँ तालिका बनाने और भरने के लिए कोड दिया गया है:

ड्रॉप टेबल अगर मौजूद है dbo.NullBits102400;GO CREATE TABLE dbo.NullBits102400(b BIT NULL, INDEX cc_NullBits102400 CLUSTERED COLUMNSTORE विथ (DATA_COMPRESSION =COLUMNSTORE B ASNULL_ARCHIVE (LAST) के रूप में COLUMNSTORE B AS (L ASCHIVE) चुनें; मान(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),( 1),(1),(1),(1)) एएस डी(बी)), एल1 एएस (एल0 से एबी को क्रॉस जॉइन एल0 एएस बी के रूप में चुनें), नल (बी) एएस (एल 1 एएस ए से एबी चुनें) क्रॉस जॉइन एल 1 एएस बी क्रॉस जॉइन एल 1 एएस सी) डीबीओ में डालें। नलबिट्स102400 (टैबलॉक) के साथ (बी) नल से टॉप (102400) बी चुनें; जाओ

लोड समय नगण्य है — मेरी मशीन पर 43 एमएस।

डिस्क पर टेबल का आकार जांचें:

EXEC sys.sp_spaceused @objname =N'dbo.NullBits102400';

मुझे डेटा के लिए आवश्यक 56 KB स्थान मिला है।

पंक्ति समूहों की संख्या, उनकी स्थिति (संपीड़ित या खुली) और उनके आकार की जाँच करें:

राज्य_विवरण, Total_rows, size_in_bytesFROM sys.column_store_row_groups से चुनें, जहां object_id =OBJECT_ID('dbo.NullBits102400');

मुझे निम्न आउटपुट मिला:

राज्य_विवरण कुल_पंक्तियों का आकार_इन_बाइट्स --------------------------------------------संपीड़ित 102400 293

यहाँ केवल एक पंक्ति समूह की आवश्यकता है; यह संकुचित है, और आकार नगण्य 293 बाइट्स है।

यदि आप तालिका को एक पंक्ति कम (102,399) के साथ पॉप्युलेट करते हैं, तो आपको एक रोस्टोर-आधारित असम्पीडित खुला डेल्टा स्टोर मिलता है। ऐसी स्थिति में sp_spaceused 1MB से अधिक की डिस्क पर डेटा आकार की रिपोर्ट करता है, और sys.column_store_row_groups निम्न जानकारी की रिपोर्ट करता है:

राज्य_विवरण कुल_पंक्तियों का आकार_इन_बाइट्स --------------------------------- खुला 102399 1499136

इसलिए सुनिश्चित करें कि आप तालिका को 102,400 पंक्तियों से भर दें!

यहाँ फ़ंक्शन की परिभाषा है dbo.GetNumsJohn2DaveObbishAlanCharlieItzik2:

 क्रिएट या अल्टर फंक्शन dbo.GetNumsJohn2DaveObbishAlanCharlieItzik2 (@low AS BIGINT =1, @high AS BIGINT) रिटर्न्स टेबल्स रिटर्न्स विद नंबर्स एएस (सेलेक्ट ROW_NUMBER () ओवर (ऑर्डर बाय (सेलेक्ट न्यूल)) एएस रोवनम के रूप में। CROSS JOIN dbo.NullBits102400 AS B) SELECT TOP(@high - @low + 1) rownum AS rn, @high + 1 - rownum AS op, @low - 1 + rownum AS n FROM Nums ORDER BY rownum;GO

Let’s test the function's performance:

DECLARE @n AS BIGINT; SELECT @n =n FROM dbo.GetNumsJohn2DaveObbishAlanCharlieItzik2(1, 100000000) OPTION(MAXDOP 1);

I got the plan shown in Figure 6 for this execution.

Figure 6:Plan for dbo.GetNumsJohn2DaveObbishAlanCharlieItzik2

I got the following time statistics for this test:

CPU time =9188 ms, elapsed time =9188 ms.

As you can see, the execution time increased by ~ 26%. It’s still pretty fast, but not as fast as the single-table solution. So that’s a tradeoff that you’ll need to evaluate.

I got the following I/O stats for this test:

Table 'NullBits102400'. Scan count 2, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 8 , lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

Table 'NullBits102400'. Segment reads 2, segment skipped 0.

The I/O profile of this solution is excellent.

Let’s add order to the test:

DECLARE @n AS BIGINT; SELECT @n =n FROM dbo.GetNumsJohn2DaveObbishAlanCharlieItzik2(1, 100000000) ORDER BY n OPTION(MAXDOP 1);

You get the same plan as shown earlier in Figure 6 since there’s no explicit sorting needed.

I got the following time statistics for this test:

CPU time =9140 ms, elapsed time =9237 ms.

And the following I/O stats:

Table 'NullBits102400'. Scan count 2, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 8 , lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.

Table 'NullBits102400'. Segment reads 2, segment skipped 0.

Again, the numbers are very similar to the test without the ordering.

Performance summary

Figure 7 has a summary of the time statistics for the different solutions.

Figure 7:Time performance summary of solutions

Figure 8 has a summary of the I/O statistics.

Figure 8:I/O performance summary of solutions

Thanks to all of you who posted ideas and suggestions in effort to create a fast number series generator. It’s a great learning experience!

We’re not done yet. Next month I’ll continue exploring additional solutions.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. वर्किंग फोल्डर सोर्स कंट्रोल का उपयोग करके डेटाबेस परिवर्तन को ट्रैक करना

  2. पढ़ी जाने वाली पंक्तियों की अनुमानित संख्या

  3. ओडीबीसी 4.0

  4. क्विकबुक ओडीबीसी चालक

  5. IRI कार्यक्षेत्र में Teradata से जुड़ना