मैं पहले 100 मिलियन पॉजिटिव पूर्णांकों को स्ट्रिंग्स में कैसे बदल सकता हूं?


13

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

मैं कुछ औपचारिक परिभाषा के साथ शुरुआत करने की कोशिश करूँगा। एक स्ट्रिंग को श्रृंखला में शामिल किया जाता है यदि इसमें केवल ए - जेड से बड़े अक्षरों का समावेश होता है। श्रृंखला का पहला शब्द "ए" है। श्रृंखला में लंबाई के आधार पर छांटे गए सभी वैध तार होते हैं और विशिष्ट वर्णमाला क्रम दूसरा होता है। यदि तार नामक एक स्तंभ में एक तालिका में थे STRING_COL, तो आदेश को टी-एसक्यूएल में परिभाषित किया जा सकता है ORDER BY LEN(STRING_COL) ASC, STRING_COL ASC

कम औपचारिक परिभाषा देने के लिए एक्सेल में वर्णमाला कॉलम हेडर पर एक नज़र डालें। श्रृंखला एक ही पैटर्न है। गौर कीजिए कि आप एक पूर्णांक को आधार संख्या 26 में कैसे बदल सकते हैं:

1 -> ए, 2 -> बी, 3 -> सी, ..., 25 -> वाई, 26 -> जेड, 27 -> एए, 28 -> एबी, ...

सादृश्य बिल्कुल सही नहीं है क्योंकि "ए" आधार दस में 0 से भिन्न व्यवहार करता है। नीचे चयनित मानों की एक तालिका दी गई है, जो उम्मीद करेंगे कि यह अधिक स्पष्ट हो:

╔════════════╦════════╗
 ROW_NUMBER  STRING 
╠════════════╬════════╣
          1  A      
          2  B      
         25  Y      
         26  Z      
         27  AA     
         28  AB     
         51  AY     
         52  AZ     
         53  BA     
         54  BB     
      18278  ZZZ    
      18279  AAAA   
     475253  ZZZY   
     475254  ZZZZ   
     475255  AAAAA  
  100000000  HJUNYV 
╚════════════╩════════╝

लक्ष्य एक SELECTक्वेरी लिखना है जो ऊपर बताए गए क्रम में पहले 100000000 तार देता है। मैंने SSMS में क्वेरीज़ चलाकर अपना परीक्षण किया, जिसके परिणाम के रूप में एक तालिका में इसे सहेजने का विरोध किया गया।

परिणाम सेट को त्यागें

आदर्श रूप से क्वेरी यथोचित कुशल होगी। यहाँ मैं एक सीरियल क्वेरी के लिए सीपीयू समय के रूप में कुशल को परिभाषित कर रहा हूं और समानांतर क्वेरी के लिए बीता हुआ समय। आप जो भी अवांछित चालें चाहें उनका उपयोग कर सकते हैं। अपरिभाषित या गैर-गारंटीकृत व्यवहार पर भरोसा करना ठीक है, लेकिन यदि आप अपने उत्तर में इसे बाहर निकालते हैं, तो इसकी सराहना की जाएगी।

ऊपर वर्णित डेटा सेट को कुशलतापूर्वक उत्पन्न करने के कुछ तरीके क्या हैं? मार्टिन स्मिथ ने कहा कि एक CLR संग्रहित प्रक्रिया शायद कई पंक्तियों के प्रसंस्करण के ओवरहेड के कारण एक अच्छा तरीका नहीं है।

जवाबों:


7

आपका समाधान मेरे लैपटॉप पर 35 सेकंड तक चलता है । निम्न कोड में 26 सेकंड लगते हैं (अस्थायी तालिकाओं को बनाने और आबाद करने के लिए):

अस्थायी टेबल

DROP TABLE IF EXISTS #T1, #T2, #T3, #T4;

CREATE TABLE #T1 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T2 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T3 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T4 (string varchar(6) NOT NULL PRIMARY KEY);

INSERT #T1 (string)
VALUES
    ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'),
    ('H'), ('I'), ('J'), ('K'), ('L'), ('M'), ('N'),
    ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'), ('U'),
    ('V'), ('W'), ('X'), ('Y'), ('Z');

INSERT #T2 (string)
SELECT T1a.string + T1b.string
FROM #T1 AS T1a, #T1 AS T1b;

INSERT #T3 (string)
SELECT #T2.string + #T1.string
FROM #T2, #T1;

INSERT #T4 (string)
SELECT #T3.string + #T1.string
FROM #T3, #T1;

इस विचार में चार वर्णों तक के आदेशों को पूर्व-आबाद करना है।

मुख्य कोड

SELECT TOP (100000000)
    UA.string + UA.string2
FROM
(
    SELECT U.Size, U.string, string2 = '' FROM 
    (
        SELECT Size = 1, string FROM #T1
        UNION ALL
        SELECT Size = 2, string FROM #T2
        UNION ALL
        SELECT Size = 3, string FROM #T3
        UNION ALL
        SELECT Size = 4, string FROM #T4
    ) AS U
    UNION ALL
    SELECT Size = 5, #T1.string, string2 = #T4.string
    FROM #T1, #T4
    UNION ALL
    SELECT Size = 6, #T2.string, #T4.string
    FROM #T2, #T4
) AS UA
ORDER BY 
    UA.Size, 
    UA.string, 
    UA.string2
OPTION (NO_PERFORMANCE_SPOOL, MAXDOP 1);

5-चरित्र और आवश्यकतानुसार 6-वर्ण स्ट्रिंग्स के साथ, चार अभिकलन तालिकाओं का एक सरल क्रम-संरक्षण संघ * है। प्रत्यय को प्रत्यय से अलग करना छँटाई से बचता है।

निष्पादन योजना

100 मिलियन पंक्तियाँ


* ऊपर SQL में ऐसा कुछ नहीं है जो सीधे ऑर्डर-प्रोटेक्शन यूनियन को निर्दिष्ट करता है। ऑप्टिमाइज़र SQL क्वेरी विनिर्देश से मेल खाने वाले गुणों के साथ भौतिक ऑपरेटरों को चुनता है, जिसमें शीर्ष-स्तरीय क्रम शामिल है। इधर, यह मर्ज द्वारा कार्यान्वित संघटन को छांटने से बचने के लिए भौतिक ऑपरेटर में शामिल हो जाता है।

गारंटी यह है कि निष्पादन योजना विनिर्देश द्वारा क्वेरी अर्थ और शीर्ष-स्तरीय आदेश वितरित करती है। यह जानते हुए कि विलय में शामिल होने के आदेश को बरकरार रखता है, क्वेरी लेखक को एक निष्पादन योजना का अनुमान लगाने की अनुमति देता है, लेकिन आशावादी केवल तभी वितरित करेगा जब अपेक्षा मान्य होगी।


6

मैं आरंभ करने के लिए उत्तर पोस्ट करूंगा। मेरा पहला विचार यह था कि नेस्टेड लूप के आदेश-संरक्षण की प्रकृति का लाभ उठाना संभव होना चाहिए, साथ ही कुछ हेल्पर टेबल के साथ जुड़ना चाहिए, जिसमें प्रत्येक अक्षर के लिए एक पंक्ति हो। मुश्किल हिस्सा इस तरह से लूपिंग हो रहा था कि परिणाम डुप्लिकेट से बचने के साथ-साथ लंबाई के अनुसार आदेश दिए गए थे। उदाहरण के लिए, जब 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_CHARALL_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 के माध्यम से क्वेरी चलाने और परिणाम सेट को छोड़ने के दौरान था। मुझे डेटा जनरेट करने के अन्य तरीकों को देखने में बहुत दिलचस्पी है।


2

मेरे पास 217,180,147,158 (8 वर्ण) तक के किसी भी विशिष्ट संख्या के लिए स्ट्रिंग कोड प्राप्त करने के लिए अनुकूलित एक समाधान है। लेकिन मैं आपके समय को हरा नहीं सकता:

SQL Server 2014 के साथ मेरी मशीन पर, आपकी क्वेरी को 18 सेकंड लगते हैं, जबकि मेरा 3m 46s लेता है। दोनों प्रश्न अप्रत्यक्ष ट्रेस ध्वज 8690 का उपयोग करते हैं क्योंकि 2014 NO_PERFORMANCE_SPOOLसंकेत का समर्थन नहीं करता है ।

यहाँ कोड है:

/* precompute offsets and powers to simplify final query */
CREATE TABLE #ExponentsLookup (
    offset          BIGINT NOT NULL,
    offset_end      BIGINT NOT NULL,
    position        INTEGER NOT NULL,
    divisor         BIGINT NOT NULL,
    shifts          BIGINT NOT NULL,
    chars           INTEGER NOT NULL,
    PRIMARY KEY(offset, offset_end, position)
);

WITH base_26_multiples AS ( 
    SELECT  number  AS exponent,
            CAST(POWER(26.0, number) AS BIGINT) AS multiple
    FROM    master.dbo.spt_values
    WHERE   [type] = 'P'
            AND number < 8
),
num_offsets AS (
    SELECT  *,
            -- The maximum posible value is 217180147159 - 1
            LEAD(offset, 1, 217180147159) OVER(
                ORDER BY exponent
            ) AS offset_end
    FROM    (
                SELECT  exponent,
                        SUM(multiple) OVER(
                            ORDER BY exponent
                        ) AS offset
                FROM    base_26_multiples
            ) x
)
INSERT INTO #ExponentsLookup(offset, offset_end, position, divisor, shifts, chars)
SELECT  ofst.offset, ofst.offset_end,
        dgt.number AS position,
        CAST(POWER(26.0, dgt.number) AS BIGINT)     AS divisor,
        CAST(POWER(256.0, dgt.number) AS BIGINT)    AS shifts,
        ofst.exponent + 1                           AS chars
FROM    num_offsets ofst
        LEFT JOIN master.dbo.spt_values dgt --> as many rows as resulting chars in string
            ON [type] = 'P'
            AND dgt.number <= ofst.exponent;

/*  Test the cases in table example */
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    (
            VALUES(1),(2),(25),(26),(27),(28),(51),(52),(53),(54),
            (18278),(18279),(475253),(475254),(475255),
            (100000000), (CAST(217180147158 AS BIGINT))
        ) ref([row_number])
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number];

/*  Test with huge set  */
WITH numbers AS (
    SELECT  TOP(100000000)
            ROW_NUMBER() OVER(
                ORDER BY x1.number
            ) AS [row_number]
    FROM    master.dbo.spt_values x1
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x3
    WHERE   x1.number < 219
)
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    numbers ref
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number]
OPTION (QUERYTRACEON 8690);

चाल यहाँ है जहाँ अलग क्रमांकन शुरू करने के लिए precompute है:

  1. जब आपको एक चार का आउटपुट देना होता है, तो आपके पास 26 ^ 0 से शुरू होने वाले 26 ^ 1 क्रमपरिवर्तन होते हैं।
  2. जब आपको 2 वर्णों का उत्पादन करना होता है तो आपके पास 26 ^ 2 क्रमांक 26 ^ 0 + 26 ^ 1 से शुरू होते हैं
  3. जब आपको 3 वर्णों का उत्पादन करना होता है तो आपके पास 26 ^ 3 क्रमांक 26 ^ 0 + 26 ^ 1 + 26 2 2 से शुरू होते हैं।
  4. एन चार के लिए दोहराएं

अन्य चाल का उपयोग केवल संक्षेपण का प्रयास करने के बजाय सही मूल्य प्राप्त करने के लिए योग का उपयोग करना है। इसे प्राप्त करने के लिए मैं केवल अंक 26 को आधार से 256 के आधार पर ऑफसेट करता हूं और प्रत्येक अंक के लिए 'ए' का एससीआई मान जोड़ता हूं। इसलिए हम उस स्ट्रिंग का बाइनरी प्रतिनिधित्व प्राप्त करते हैं जिसे हम खोज रहे हैं। उसके बाद कुछ स्ट्रिंग जोड़तोड़ प्रक्रिया को पूरा करते हैं।


-1

ठीक है, यहाँ मेरी नवीनतम स्क्रिप्ट जाती है।

नो लूप, नो रिकर्सिव।

यह केवल 6 char के लिए काम करता है

सबसे बड़ी खामी यह 1,00,00,000 के लिए लगभग 22 मिनट है

इस बार मेरी स्क्रिप्ट बहुत कम है।

SET NoCount on

declare @z int=26
declare @start int=@z+1 
declare @MaxLimit int=10000000

SELECT TOP (@MaxLimit) IDENTITY(int,1,1) AS N
    INTO NumbersTest1
    FROM     master.dbo.spt_values x1   
   CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x3
    WHERE   x1.number < 219
ALTER TABLE NumbersTest1 ADD CONSTRAINT PK_NumbersTest1 PRIMARY KEY CLUSTERED (N)


select N, strCol from NumbersTest1
cross apply
(
select 
case when IntCol6>0 then  char((IntCol6%@z)+64) else '' end 
+case when IntCol5=0 then 'Z' else isnull(char(IntCol5+64),'') end 
+case when IntCol4=0 then 'Z' else isnull(char(IntCol4+64),'') end 
+case when IntCol3=0 then 'Z' else isnull(char(IntCol3+64),'') end 
+case when IntCol2=0 then 'Z' else isnull(char(IntCol2+64),'') end 
+case when IntCol1=0 then 'Z' else isnull(char(IntCol1+64),'') end strCol
from
(
select  IntCol1,IntCol2,IntCol3,IntCol4
,case when IntCol5>0 then  IntCol5%@z else null end IntCol5

,case when IntCol5/@z>0 and  IntCol5%@z=0 then  IntCol5/@z-1 
when IntCol5/@z>0 then IntCol5/@z
else null end IntCol6
from
(
select IntCol1,IntCol2,IntCol3
,case when IntCol4>0 then  IntCol4%@z else null end IntCol4

,case when IntCol4/@z>0 and  IntCol4%@z=0 then  IntCol4/@z-1 
when IntCol4/@z>0 then IntCol4/@z
else null end IntCol5
from
(
select IntCol1,IntCol2
,case when IntCol3>0 then  IntCol3%@z else null end IntCol3
,case when IntCol3/@z>0 and  IntCol3%@z=0 then  IntCol3/@z-1 
when IntCol3/@z>0 then IntCol3/@z
else null end IntCol4

from
(
select IntCol1
,case when IntCol2>0 then  IntCol2%@z else null end IntCol2
,case when IntCol2/@z>0 and  IntCol2%@z=0 then  IntCol2/@z-1 
when IntCol2/@z>0 then IntCol2/@z
else null end IntCol3

from
(
select case when N>0 then N%@z else null end IntCol1
,case when N%@z=0 and  (N/@z)>1 then (N/@z)-1 else  (N/@z) end IntCol2 

)Lv2
)Lv3
)Lv4
)Lv5
)LV6

)ca

DROP TABLE NumbersTest1

ऐसा लगता है कि व्युत्पन्न तालिका एक एकल गणना स्केलर में परिवर्तित हो जाती है जो कोड के 400000 से अधिक वर्ण हैं। मुझे संदेह है कि उस गणना के लिए बहुत अधिक ओवरहेड है। आप निम्नलिखित के समान कुछ आज़माना चाह सकते हैं: dbfiddle.uk/… अपने जवाब में उस के घटकों को एकीकृत करने के लिए स्वतंत्र महसूस करें।
जो ओबिश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.