क्यों मेरा आदेश EXCEPT (धीमी) से पहले दो तालिकाओं को क्रमबद्ध करता है और (तेज) के बाद नहीं?


12

SQL सर्वर 2008 R2 क्वेरी ऑप्टिमाइज़र पहेली

हमारे पास दो टेबल हैं, दोनों में 9 मिलियन पंक्तियाँ हैं। 70.000 पंक्तियाँ अलग हैं, अन्य समान हैं।

यह तेजी से, 13 सेकंड है,

select * from bigtable1
except select * from similar_bigtable2

यह आउटपुट को सॉर्ट करता है और तेज़ भी है, साथ ही 13 सेकंड

select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column

जबकि यह काफी धीमा है:

;with q as (
    select * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

और यहां तक ​​कि एक "ट्रिक" जिसे मैं कभी-कभी एसक्यूएल सर्वर को इंगित करने के लिए उपयोग करता हूं कि इसे चलने से पहले क्वेरी के एक निश्चित हिस्से को पहले से निर्धारित करने की आवश्यकता है, काम नहीं करता है और धीमी क्वेरी में भी परिणाम करता है:

;with q as (
    select top 100 percent * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

क्वेरी योजनाओं को देखने के कारण को खोजना मुश्किल नहीं है:

क्वेरी योजना आदेश के साथ क्वेरी योजना

हैशमैच से पहले SQL सर्वर दो तरह की 9 मिलियन पंक्तियों को रखता है, जबकि मैं इसे पसंद करूँगा कि हैशमैच के बाद केवल एक प्रकार की 70.000 पंक्तियों को जोड़ा जाए।

तो सवाल: मैं क्वेरी ऑप्टिमाइज़र को ऐसा करने का निर्देश कैसे दे सकता हूं?


3
यह हैशमैच से पहले सॉर्ट नहीं करता है, यह सॉर्ट करता है और फिर मर्ज-जॉइन करता है (हैश-जॉइन नहीं)। शायद हैश-जॉइन (या मर्ज-जॉइन को रोकने) के लिए मजबूर करने का संकेत है?
थिलो

3
ऐसा लगता है कि SQL सर्वर क्वेरी ऑप्टिमाइज़र ने निर्धारित किया था कि डेटा को सॉर्ट करना फायदेमंद था, इसलिए यह बहुत धीमे मर्ज जॉइन का उपयोग कर सकता है (जो केवल सॉर्ट किए गए डेटा के लिए काम करता है) के बजाय बहुत धीमी हैश मैच जॉइन या नेस्टेड लूप जॉइन करें ....
marc.s

9
क्या आपने EXCEPT(जैसे OUTER JOIN) विकल्प का प्रयास किया है ? मुझे लगता है कि वाक्यविन्यास कम सुविधाजनक है, लेकिन आप सूचकांक के साथ खेलने में सक्षम हो सकते हैं या वहां बेहतर संकेत जोड़ सकते हैं (या आपको इसकी आवश्यकता नहीं हो सकती है)। अब आप जिस विकल्प का उपयोग कर रहे हैं (पहले एक # टेबल में सामान) एक अंतिम रिज़ॉर्ट वर्कअराउंड है, लेकिन कुछ मामलों में ऑप्टिमाइज़र को क्वेरी के दो हिस्सों को पूरी तरह से अलग करने के लिए मजबूर करने का एकमात्र तरीका है जो आप चाहते हैं।
हारून बर्ट्रेंड

जवाबों:


1

इन दोनों क्वेरी योजनाओं के बीच मुख्य अंतर वास्तव में हैश मैच और मर्ज जॉइन के अंतर में है। हैश मैच अधिक कुशल है और जैसा कि आप विकल्प 1 में तेजी से रन देख सकते हैं (सीटीई का उपयोग नहीं कर रहे हैं)।

CTE एक बेहतरीन टूल है, लेकिन लगता है कि यह दो मामलों में जटिल नहीं है, कॉम्प्लेक्स प्रेडिकेट्स या नॉन-यूनीक पेरेंट / चाइल्ड की। आपके मामले में कोई अनोखी कुंजी नहीं है और SQL सर्वर को आपकी आवश्यकता को पूरा करने में सक्षम होने के लिए पहले डेटा सेट को सॉर्ट करना होगा। नीचे दिए गए लिंक पर एक नज़र डालें जो आपको इस मुद्दे पर और अधिक बताता है: http://blogs.msdn.com/b/sqlcat/archive/2011/04/28/optimize-recursive-cte-query.aspx

तो ऐसा लगता है कि या तो आपको इसकी सुस्ती को स्वीकार करना होगा या फिर WHILE लूप के साथ तर्क को फिर से लिखना होगा जो अधिक कुशल हो सकता है।



0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.