2009-09-08 2 views
10

मैं तालिका के मूल्यवान फ़ंक्शन से कुछ पंक्तियों का चयन कर रहा हूं लेकिन क्वेरी में SELECT TOP डालकर एक अतुलनीय बड़े पैमाने पर प्रदर्शन अंतर पाया है।SELECT TOP x का उपयोग करके एसक्यूएल बड़े पैमाने पर प्रदर्शन अंतर, जब एक्स चयनित पंक्तियों से अधिक है

SELECT col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

पूरा करने के लिए 5 या 6 मिनट के ऊपर ले रहा है।

हालांकि

SELECT TOP 6000 col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

के बारे में 4 या 5 सेकंड में पूरा करता है।

यह मुझे आश्चर्य नहीं करेगा अगर डेटा का लौटा सेट विशाल था, लेकिन 200,000 में से 5000 पंक्तियों में शामिल विशेष क्वेरी शामिल है।

इसलिए दोनों मामलों में, पूरी तालिका को संसाधित किया जाता है, क्योंकि SQL सर्वर 6000 पंक्तियों की खोज में अंत तक जारी रहता है जो इसे कभी नहीं मिलेगा। तब बड़ा अंतर क्यों? क्या एसक्यूएल सर्वर परिणाम सेट आकार की अपेक्षा में अंतरिक्ष आवंटित करता है (शीर्ष 6000 जिससे यह कम आवश्यकता देता है जिसे स्मृति में अधिक आसानी से आवंटित किया जाता है)? क्या किसी और ने ऐसा कुछ देखा है?

धन्यवाद

+0

क्या आपने क्वेरी योजनाओं को देखा है? क्या कोई अंतर है? –

+2

बस उत्सुक है, यदि आप शीर्ष 100 PERCENT चुनते हैं तो प्रदर्शन के साथ क्या होता है ....? –

+0

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

उत्तर

6

तालिका मूल्यवान कार्यों में एक गैर-रैखिक निष्पादन समय हो सकता है।

के इस प्रश्न के लिए समारोह बराबर पर विचार करें:

SELECT (
     SELECT SUM(mi.value) 
     FROM mytable mi 
     WHERE mi.id <= mo.id 
     ) 
FROM mytable mo 
ORDER BY 
     mo.value 

इस क्वेरी (कि गणना करता है SUM चल) शुरुआत और अंत में धीमी गति से पर तेज है, mo से प्रत्येक पंक्ति पर है, क्योंकि यह सब योग करना चाहिए पिछले मान जो rowsource rewinding की आवश्यकता है।

पंक्ति संख्या में वृद्धि के रूप में प्रत्येक पंक्ति के लिए SUM की गणना करने के लिए समय लिया गया।

यदि आप mytable को पर्याप्त रूप से पर्याप्त कहते हैं (100,000 पंक्तियां, उदाहरण के अनुसार) और इस क्वेरी को चलाएं तो आप देखेंगे कि इसमें काफी समय लगता है।

हालांकि, यदि आप इस क्वेरी में TOP 5000 लागू करते हैं तो आप देखेंगे कि यह पूर्ण तालिका के लिए आवश्यक समय के 1/20 से अधिक तेज़ है।

शायद, आपके मामले में कुछ ऐसा ही होता है।

कुछ और निश्चित रूप से कहने के लिए, मुझे फ़ंक्शन परिभाषा देखने की आवश्यकता है।

अद्यतन:

SQL Server समारोह में विधेय धक्का कर सकते हैं।

CREATE FUNCTION fn_test() 
RETURNS TABLE 
AS 
RETURN (
     SELECT * 
     FROM master 
     ); 

इन क्वेरी:

उदाहरण के लिए, मैं सिर्फ इस TVF बनाया

SELECT * 
FROM fn_test() 
WHERE name = @name 

SELECT TOP 1000 * 
FROM fn_test() 
WHERE name = @name 

उपज अलग निष्पादन की योजना (पहले एक क्लस्टर का उपयोग करता है स्कैन, दूसरा एक एक सूचकांक के साथ की तलाश का उपयोग करता है TOP)

+0

'इस मामले में Fraid नहीं उपयोग करने का प्रयास करने के बीच अंतर है। मेरी क्वेरी का मुद्दा यह है कि _same_ पंक्तियां इस बात पर ध्यान दिए बिना हैं कि यह शीर्ष क्लॉज का उपयोग किया गया है या नहीं (शीर्ष 6000 परिणाम सेट से बड़ा है)। इसलिए यह उन पंक्तियों की गणना के साथ नहीं किया जा सकता है। – Ray

+0

'@ अर्ज ': क्या आप अपनी कार्य परिभाषा पोस्ट कर सकते हैं? – Quassnoi

+0

@Quassnoi: इनलाइन टीवीएफ बस एक मैक्रो है। – gbn

1

यह जरूरी नहीं है कि अगर कॉल 1 में इंडेक्स हो तो पूरी तालिका संसाधित हो जाती है।

एसक्यूएल अनुकूलन यह चुनता है कि इंडेक्स का उपयोग करना है या नहीं। शायद आपका "टॉप" इंडेक्स का उपयोग करने के लिए मजबूर कर रहा है।

यदि आप एमएसएसक्यूएल क्वेरी विश्लेषक (नाम मुझसे बच निकला है) का उपयोग कर रहे हैं तो Ctrl-K दबाएं। यह निष्पादन के बजाय क्वेरी के लिए निष्पादन योजना दिखाएगा। आइकन पर आवास आईओ/सीपीयू उपयोग दिखाएगा, मुझे विश्वास है।

मुझे लगता है कि कोई एक इंडेक्स खोज का उपयोग कर रहा है, जबकि दूसरा नहीं है।

यदि आपके पास एक सामान्य ग्राहक है: सेट SHOWPLAN_ALL चालू; जाओ का चयन करें ...;

विवरण के लिए http://msdn.microsoft.com/en-us/library/ms187735.aspx देखें।

+0

हाँ - मैं अभी इस योजना को देख रहा हूं। हालांकि मैंने पोस्टिंग के लिए क्वेरी बदल दी है। हकीकत में यह चयन * कर रहा है। मैं नहीं देख सकता कि टॉप का उपयोग कैसे सूचकांक का उपयोग करेगा? – Ray

+0

एसक्यूएल ऑप्टिमाइज़र तय करेगा कि इंडेक्स का उपयोग करना है या नहीं। मैंने प्रश्न पूछे हैं जहां क्लॉज "टिपिंग पॉइंट" का कारण बनता है जहां ऑप्टिमाइज़र इंडेक्स का उपयोग करने के बजाय पूर्ण टेबल स्कैन करने का निर्णय लेता है। – ericp

1

आप यहां कैशिंग के रूप में सरल कुछ चल रहे हो सकते हैं - शायद (किसी भी कारण से) "टॉप" क्वेरी कैश की गई है? एक इंडेक्स का उपयोग करना जो दूसरा नहीं है?

किसी भी मामले में अपनी जिज्ञासा को बुझाने का सबसे अच्छा तरीका दोनों प्रश्नों के लिए पूर्ण निष्पादन योजना की जांच करना है। आप एसक्यूएल मैनेजमेंट कंसोल में यह सही कर सकते हैं और यह आपको बताएगा कि कौन से ऑपरेशन पूरे किए जा रहे हैं और कब तक प्रत्येक को लेने की भविष्यवाणी की जाती है।

सभी SQL कार्यान्वयन अपने तरीके से quirky हैं - SQL सर्वर का कोई अपवाद नहीं है। इस तरह का "व्हाउआ ?!" क्षण बहुत आम हैं। ; ^)

3

आपके टॉप के पास कोई ऑर्डर नहीं है, इसलिए यह बस SET ROWCOUNT 6000 जैसा ही है। एक आदेश के अनुसार सभी पंक्तियों का मूल्यांकन पहले किया जाएगा, और इसमें बहुत अधिक समय लगेगा।

यदि dbo.some_table_function एक इनलाइन तालिका मूल्यवान udf है, तो यह केवल एक मैक्रो है जिसे विस्तारित किया गया है, इसलिए यह किसी भी विशेष क्रम में उल्लिखित पहली 6000 पंक्तियां देता है।

यदि udf बहु मूल्यवान है, तो यह एक काला बॉक्स है और हमेशा फ़िल्टरिंग से पहले पूर्ण डेटासेट में खींच जाएगा। मुझे नहीं लगता कि यह हो रहा है।

सीधे संबंधित नहीं है, लेकिन another SO question on TVFs

1

मुझे लगता है कि Quassnois 'सुझाव बहुत प्रशंसनीय लगता है। शीर्ष 6000 जोड़कर आप स्पष्ट रूप से ऑप्टिमाइज़र को एक संकेत दे रहे हैं कि 200,000 पंक्तियों का एक छोटा सा सबसेट वापस किया जा रहा है। ऑप्टिमाइज़र तब क्लस्टर्ड इंडेक्स स्कैन या टेबल स्कैन की बजाय इंडेक्स की तलाश करता है।

जिम डेविस सुझाव देते हैं, एक और संभावित स्पष्टीकरण कैशिंग कर सकता है। प्रश्नों को फिर से चलाकर इसे रद्द करना काफी आसान है। पहले शीर्ष 6000 के साथ एक को चलाने का प्रयास करें।

2

मुझे एक ही समस्या थी, 1000 पंक्तियों को लौटने वाली पांच तालिकाओं में शामिल होने वाली एक साधारण क्वेरी को पूरा होने में दो मिनट लग गए। जब मैंने इसे "टॉप 10000" जोड़ा तो यह एक सेकंड से भी कम समय में पूरा हुआ। यह पता चला कि टेबल में से एक पर क्लस्टर इंडेक्स भारी खंडित था।

इंडेक्स के पुनर्निर्माण के बाद क्वेरी अब एक सेकंड से भी कम समय में पूर्ण हो जाती है।

संबंधित मुद्दे