मैं आरंभ करने के लिए उत्तर पोस्ट करूंगा। मेरा पहला विचार यह था कि नेस्टेड लूप के आदेश-संरक्षण की प्रकृति का लाभ उठाना संभव होना चाहिए, साथ ही कुछ हेल्पर टेबल के साथ जुड़ना चाहिए, जिसमें प्रत्येक अक्षर के लिए एक पंक्ति हो। मुश्किल हिस्सा इस तरह से लूपिंग हो रहा था कि परिणाम डुप्लिकेट से बचने के साथ-साथ लंबाई के अनुसार आदेश दिए गए थे। उदाहरण के लिए, जब CTE में '26' के साथ सभी 26 कैपिटल लेटर्स शामिल होते हैं, तो आप जनरेटिंग को समाप्त कर सकते हैं 'A' + '' + 'A'और '' + 'A' + 'A'जो निश्चित रूप से एक ही स्ट्रिंग है।
पहला निर्णय यह था कि हेल्पर का डेटा कहां रखा जाए। मैंने एक अस्थायी तालिका का उपयोग करने की कोशिश की, लेकिन प्रदर्शन पर आश्चर्यजनक रूप से नकारात्मक प्रभाव पड़ा, भले ही डेटा एक पृष्ठ में फिट हो। अस्थायी तालिका में निम्न डेटा शामिल थे:
SELECT 'A'
UNION ALL SELECT 'B'
...
UNION ALL SELECT 'Y'
UNION ALL SELECT 'Z'
CTE का उपयोग करने की तुलना में, क्वेरी ने 3X लंबे समय तक एक संकुल तालिका के साथ और 4X लंबे समय तक एक ढेर के साथ लिया। मुझे विश्वास नहीं है कि समस्या यह है कि डेटा डिस्क पर है। इसे एक पेज के रूप में मेमोरी में पढ़ा जाना चाहिए और पूरे प्लान के लिए मेमोरी में प्रोसेस करना चाहिए। शायद SQL सर्वर लगातार स्कैन ऑपरेटर से डेटा के साथ अधिक कुशलता से काम कर सकता है, जो कि विशिष्ट रोस्टोरेंट पृष्ठों में संग्रहीत डेटा के साथ हो सकता है।
दिलचस्प बात यह है कि एसक्यूएल सर्वर ऑर्डर किए गए डेटा को टेबल स्पूल में डेटा के साथ सिंगल पेज टेम्पर्ड टेबल से रखना चाहता है:

एसक्यूएल सर्वर अक्सर क्रॉस के आंतरिक तालिका के लिए परिणाम तालिका स्पूल में शामिल हो जाता है, भले ही ऐसा करने के लिए निरर्थक लगता है। मुझे लगता है कि इस क्षेत्र में आशावादी को थोड़ा काम करने की जरूरत है। मैंने NO_PERFORMANCE_SPOOLप्रदर्शन हिट से बचने के लिए क्वेरी को चलाया ।
सहायक डेटा को संग्रहीत करने के लिए CTE के उपयोग के साथ एक समस्या यह है कि डेटा को ऑर्डर करने की गारंटी नहीं है। मैं यह नहीं सोच सकता कि ऑप्टिमाइज़र इसे ऑर्डर करने के लिए क्यों नहीं चुनेगा और मेरे सभी परीक्षणों में डेटा को उस क्रम में संसाधित किया गया था जिसे मैंने सीटीई लिखा था:

हालांकि, किसी भी मौके को लेने के लिए सबसे अच्छा नहीं है, खासकर अगर एक बड़े प्रदर्शन के बिना इसे करने का एक तरीका है ओवरहेड। एक अति सुंदर TOPऑपरेटर को जोड़कर एक व्युत्पन्न तालिका में डेटा को ऑर्डर करना संभव है । उदाहरण के लिए:
(SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR)
क्वेरी के अतिरिक्त यह गारंटी दी जानी चाहिए कि परिणाम सही क्रम में वापस आ जाएंगे। मुझे उम्मीद है कि सभी प्रकार के बड़े नकारात्मक प्रदर्शन का असर पड़ेगा। क्वेरी ऑप्टिमाइज़र ने अनुमानित लागत के आधार पर इसकी अपेक्षा की:

बहुत आश्चर्यजनक रूप से, मैं स्पष्ट आदेश के साथ या बिना सीपीयू समय या रनटाइम में किसी भी सांख्यिकीय महत्वपूर्ण अंतर का निरीक्षण नहीं कर सका। यदि कुछ भी हो, तो क्वेरी को तेज़ी से चलाना प्रतीत होता है ORDER BY! इस व्यवहार के लिए मेरे पास कोई स्पष्टीकरण नहीं है।
समस्या का मुश्किल हिस्सा यह पता लगाना था कि रिक्त स्थानों को सही स्थानों पर कैसे डाला जाए। जैसा कि पहले बताया गया है कि CROSS JOINडुप्लिकेट डेटा में परिणाम होगा। हम जानते हैं कि 100000000 वें तार की लंबाई छह वर्णों की होगी क्योंकि:
26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 = 914654 <100000000
परंतु
26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 + 26 ^ 6 = 321272406> 100000000
इसलिए हमें केवल छह बार सीटीई पत्र में शामिल होने की आवश्यकता है। मान लीजिए कि हम छह बार सीटीई में शामिल होते हैं, प्रत्येक सीटीई से एक पत्र को पकड़ो, और उन सभी को एक साथ सम्मिलित करें। मान लीजिए कि सबसे बाईं ओर का अक्षर रिक्त नहीं है। यदि बाद के कोई भी अक्षर रिक्त हैं, जिसका अर्थ है कि स्ट्रिंग छह वर्णों से कम है, तो यह एक डुप्लिकेट है। इसलिए, हम पहले गैर-रिक्त वर्ण को ढूंढकर डुप्लिकेट को रोक सकते हैं और सभी वर्णों की आवश्यकता के बाद भी इसे खाली नहीं कर सकते हैं। मैंने FLAGCTE में से एक को एक कॉलम असाइन करके और WHEREक्लॉज़ में एक चेक जोड़कर इसे ट्रैक करने के लिए चुना । क्वेरी को देखने के बाद यह अधिक स्पष्ट होना चाहिए। अंतिम प्रश्न इस प्रकार है:
WITH FIRST_CHAR (CHR) AS
(
SELECT 'A'
UNION ALL SELECT 'B'
UNION ALL SELECT 'C'
UNION ALL SELECT 'D'
UNION ALL SELECT 'E'
UNION ALL SELECT 'F'
UNION ALL SELECT 'G'
UNION ALL SELECT 'H'
UNION ALL SELECT 'I'
UNION ALL SELECT 'J'
UNION ALL SELECT 'K'
UNION ALL SELECT 'L'
UNION ALL SELECT 'M'
UNION ALL SELECT 'N'
UNION ALL SELECT 'O'
UNION ALL SELECT 'P'
UNION ALL SELECT 'Q'
UNION ALL SELECT 'R'
UNION ALL SELECT 'S'
UNION ALL SELECT 'T'
UNION ALL SELECT 'U'
UNION ALL SELECT 'V'
UNION ALL SELECT 'W'
UNION ALL SELECT 'X'
UNION ALL SELECT 'Y'
UNION ALL SELECT 'Z'
)
, ALL_CHAR (CHR, FLAG) AS
(
SELECT '', 0 CHR
UNION ALL SELECT 'A', 1
UNION ALL SELECT 'B', 1
UNION ALL SELECT 'C', 1
UNION ALL SELECT 'D', 1
UNION ALL SELECT 'E', 1
UNION ALL SELECT 'F', 1
UNION ALL SELECT 'G', 1
UNION ALL SELECT 'H', 1
UNION ALL SELECT 'I', 1
UNION ALL SELECT 'J', 1
UNION ALL SELECT 'K', 1
UNION ALL SELECT 'L', 1
UNION ALL SELECT 'M', 1
UNION ALL SELECT 'N', 1
UNION ALL SELECT 'O', 1
UNION ALL SELECT 'P', 1
UNION ALL SELECT 'Q', 1
UNION ALL SELECT 'R', 1
UNION ALL SELECT 'S', 1
UNION ALL SELECT 'T', 1
UNION ALL SELECT 'U', 1
UNION ALL SELECT 'V', 1
UNION ALL SELECT 'W', 1
UNION ALL SELECT 'X', 1
UNION ALL SELECT 'Y', 1
UNION ALL SELECT 'Z', 1
)
SELECT TOP (100000000)
d6.CHR + d5.CHR + d4.CHR + d3.CHR + d2.CHR + d1.CHR
FROM (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d6
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d5
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d4
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d3
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d2
CROSS JOIN (SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR) d1
WHERE (d2.FLAG + d3.FLAG + d4.FLAG + d5.FLAG + d6.FLAG) =
CASE
WHEN d6.FLAG = 1 THEN 5
WHEN d5.FLAG = 1 THEN 4
WHEN d4.FLAG = 1 THEN 3
WHEN d3.FLAG = 1 THEN 2
WHEN d2.FLAG = 1 THEN 1
ELSE 0 END
OPTION (MAXDOP 1, FORCE ORDER, LOOP JOIN, NO_PERFORMANCE_SPOOL);
CTE को ऊपर वर्णित किया गया है। ALL_CHARपांच बार शामिल हुआ क्योंकि इसमें एक खाली चरित्र के लिए एक पंक्ति शामिल है। स्ट्रिंग में अंतिम चरित्र खाली कभी नहीं होना चाहिए ताकि एक अलग CTE इसके लिए परिभाषित किया गया है, FIRST_CHAR। ALL_CHARऊपर बताए गए डुप्लिकेट को रोकने के लिए अतिरिक्त ध्वज स्तंभ का उपयोग किया जाता है। इस जाँच को करने के लिए एक अधिक कुशल तरीका हो सकता है लेकिन निश्चित रूप से इसे करने के लिए अधिक अक्षम तरीके हैं। मेरे साथ एक प्रयास LEN()और POWER()क्वेरी को वर्तमान संस्करण की तुलना में छह गुना धीमा बना दिया।
MAXDOP 1और FORCE ORDERसंकेत यह सुनिश्चित करें कि आदेश क्वेरी में संरक्षित है बनाने के लिए आवश्यक हैं। एक अनुमानित अनुमानित योजना यह देखने में मददगार हो सकती है कि जोड़ उनके वर्तमान क्रम में क्यों हैं:

क्वेरी प्लान को अक्सर दाएं से बाएं पढ़ा जाता है लेकिन पंक्ति अनुरोध बाएं से दाएं होता है। आदर्श रूप से, SQL सर्वर d1निरंतर स्कैन ऑपरेटर से बिल्कुल 100 मिलियन पंक्तियों का अनुरोध करेगा । जैसा कि आप बाएं से दाएं चलते हैं, मैं अपेक्षा करता हूं कि प्रत्येक ऑपरेटर से कम पंक्तियों का अनुरोध किया जाए। हम वास्तविक निष्पादन योजना में इसे देख सकते हैं । इसके अतिरिक्त, नीचे SQL संतरी प्लान एक्सप्लोरर का एक स्क्रीनशॉट है:

हमें d1 से बिल्कुल 100 मिलियन पंक्तियाँ मिलीं जो अच्छी बात है। ध्यान दें कि d2 और d3 के बीच पंक्तियों का अनुपात लगभग 27: 1 (165336 * 27 = 4464072) है, जो समझ में आता है कि अगर आप यह सोचते हैं कि क्रॉस जॉइन कैसे होगा। D1 और d2 के बीच पंक्तियों का अनुपात 22.4 है जो कुछ व्यर्थ कार्यों का प्रतिनिधित्व करता है। मेरा मानना है कि अतिरिक्त पंक्तियाँ डुप्लिकेट्स से हैं (स्ट्रिंग्स के बीच में खाली अक्षरों के कारण) जो इसे नेस्टेड लूप से नहीं बनाते हैं जो ऑपरेटर को फ़िल्टर करता है।
LOOP JOINक्योंकि एक संकेत तकनीकी रूप से अनावश्यक है CROSS JOINकर सकते हैं केवल एक पाश के रूप में लागू किया जा एसक्यूएल सर्वर में शामिल हो। NO_PERFORMANCE_SPOOLअनावश्यक तालिका spooling को रोकने के लिए है। स्पूल संकेत को स्वीकार करते हुए क्वेरी को मेरी मशीन पर 3X लंबे समय तक ले जाना चाहिए।
अंतिम क्वेरी में लगभग 17 सेकंड का कुल समय और 18 सेकंड का कुल व्यतीत समय है। यह SSMS के माध्यम से क्वेरी चलाने और परिणाम सेट को छोड़ने के दौरान था। मुझे डेटा जनरेट करने के अन्य तरीकों को देखने में बहुत दिलचस्पी है।