UNKNOWN के लिए VARIABLES बनाम Recompile बनाम OPTIMIZE में सूँघने का पैरामीटर


40

इसलिए हमारे पास आज सुबह एक लंबी चलने वाली समस्या थी (30 सेकंड + रन टाइम)। हमने यह देखने के लिए जाँच करने का निर्णय लिया कि क्या पैरामीटर सूँघना दोष है। इसलिए, हम खरीद को फिर से लिखते हैं और आने वाले मापदंडों को चर पर सेट करते हैं ताकि पैरामीटर सूँघने को पराजित कर सकें। एक कोशिश की / सच दृष्टिकोण। BAM, क्वेरी समय में सुधार (1 सेकंड से कम)। जब क्वेरी प्लान को देखते हुए सुधार एक इंडेक्स में पाया गया था जिसका मूल उपयोग नहीं कर रहा था।

बस यह सत्यापित करने के लिए कि हमें एक झूठी सकारात्मक नहीं मिली, हमने मूल खरीद और रीरान पर एक dbcc फ्रीप्रोचेस किया, यह देखने के लिए कि क्या बेहतर परिणाम समान होंगे। लेकिन, हमारे आश्चर्य के लिए मूल खरीद अभी भी धीमी गति से चली। हमने फिर से धीमी गति से चलने के साथ एक कोशिश की, (हमने खरीद के लिए कॉल पर एक recompile की कोशिश की और खरीद के अंदर)। हमने सर्वर को पुनः आरंभ किया (स्पष्ट रूप से देव बॉक्स)।

तो, मेरा सवाल यह है ... जब हम एक खाली प्लान कैश पर समान धीमी क्वेरी प्राप्त कर सकते हैं तो स्निफिंग पैरामीटर को दोष कैसे दिया जा सकता है ... स्निफ़ के लिए कोई पैरामीटर नहीं होना चाहिए ???

क्या हम इसके बजाय टेबल के आँकड़े से प्रभावित हो रहे हैं जो योजना कैश से संबंधित नहीं हैं। और यदि हां, तो आने वाले मापदंडों को चर मदद में क्यों सेट किया जाएगा ??

आगे की जांच में हम यह भी पाया कि विकल्प (अनुकूलन के लिए अज्ञात) proc के आंतरिक भागों पर डालने DID की उम्मीद सुधार योजना मिलता है।

तो, आप में से कुछ लोग मुझसे ज्यादा होशियार हैं, क्या आप इस प्रकार के परिणाम उत्पन्न करने के लिए पर्दे के पीछे चल रहे व्हाट्सएप को कुछ सुराग दे सकते हैं?

एक अन्य नोट पर, धीमी योजना भी कारण के साथ GoodEnoughPlanFoundजल्दी समाप्त हो जाती है जबकि तेज योजना का वास्तविक योजना में कोई प्रारंभिक गर्भपात कारण नहीं है।

संक्षेप में

  • आने वाले मापदंडों से बाहर चर बनाने (1 सेकंड)
  • recompile के साथ (30 सेकंड)
  • डीबीसीसी फ्रीप्रोचेस (30 सेकंड)
  • विकल्प (यूके के लिए ऑप्टिमाइज़) (1 सेकंड)

अद्यतन करें:

धीमी गति से निष्पादन योजना यहाँ देखें: https://www.dropbox.com/s/cmx2lrsea8q8mr6/plan_slow/xml

तेज़ निष्पादन योजना यहाँ देखें: https://www.dropbox.com/s/b28x6a01w7dxsed/plan_fast.xml

नोट: सुरक्षा कारणों से तालिका, स्कीमा, ऑब्जेक्ट नाम बदल गए।

जवाबों:


43

क्वेरी है

SELECT SUM(Amount) AS SummaryTotal
FROM   PDetail WITH(NOLOCK)
WHERE  ClientID = @merchid
       AND PostedDate BETWEEN @datebegin AND @dateend 

तालिका में 103,129,000 पंक्तियाँ हैं।

फास्ट प्लान क्लाइंटआईड द्वारा डेट पर अवशिष्ट के साथ दिखता है लेकिन पुनः प्राप्त करने के लिए 96 लुकअप करने की आवश्यकता है Amount<ParameterList>योजना में खंड इस प्रकार है।

        <ParameterList>
          <ColumnReference Column="@dateend" 
                           ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
          <ColumnReference Column="@datebegin" 
                           ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
          <ColumnReference Column="@merchid" 
                           ParameterRuntimeValue="(78155)" />
        </ParameterList>

धीमी योजना तिथि तक दिखती है और क्लाइंटआईड पर अवशिष्ट का मूल्यांकन करने और राशि प्राप्त करने के लिए लुकअप (अनुमानित 1 बनाम वास्तविक 7,388,383) है। <ParameterList>अनुभाग है

        <ParameterList>
          <ColumnReference Column="@EndDate" 
                           ParameterCompiledValue="'2013-02-01 23:59:00.000'" 
                           ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
          <ColumnReference Column="@BeginDate" 
                           ParameterCompiledValue="'2013-01-01 00:00:00.000'"               
                           ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
          <ColumnReference Column="@ClientID" 
                           ParameterCompiledValue="(78155)" 
                           ParameterRuntimeValue="(78155)" />
        </ParameterList>

इस दूसरे मामले में ParameterCompiledValueहै नहीं खाली। SQL सर्वर क्वेरी में उपयोग किए गए मानों को सफलतापूर्वक सूँघता है।

"SQL सर्वर 2005 प्रैक्टिकल समस्या निवारण" पुस्तक में स्थानीय चर का उपयोग करने के बारे में कहा गया है

हार पैरामीटर सूंघने के लिए स्थानीय चर का उपयोग करना एक बहुत ही आम चाल है, लेकिन OPTION (RECOMPILE)और OPTION (OPTIMIZE FOR)संकेत ... आम तौर पर और अधिक सुरुचिपूर्ण और थोड़ा कम जोखिम भरा समाधान कर रहे हैं


ध्यान दें

SQL सर्वर 2005 में, कथन स्तर संकलन संकलन क्वेरी के पहले निष्पादन से ठीक पहले तक संग्रहीत कार्यविधि में एक व्यक्तिगत कथन के संकलन के लिए अनुमति देता है। तब तक स्थानीय चर का मान ज्ञात हो जाएगा। सैद्धांतिक रूप से SQL सर्वर स्थानीय चर मानों को उसी तरह से सूँघ सकता है, जिस तरह से यह मापदंडों को सूँघता है। हालाँकि, क्योंकि SQL Server 7.0 और SQL Server 2000+ में सूँघने के पैरामीटर को पराजित करने के लिए स्थानीय चर का उपयोग करना आम था, SQL Server 2005 में स्थानीय चर को सूँघना सक्षम नहीं था। यह भविष्य में SQL सर्वर रिलीज़ में सक्षम हो सकता है, जो एक अच्छा है इस अध्याय में उल्लिखित अन्य विकल्पों में से एक का उपयोग करने का कारण यदि आपके पास कोई विकल्प है।


एक त्वरित परीक्षण से यह अंत व्यवहार ऊपर वर्णित वह 2008 और 2012 में एक ही है और चर आस्थगित संकलन के लिए सूंघा नहीं कर रहे हैं, लेकिन केवल जब एक स्पष्ट OPTION RECOMPILEसंकेत किया जाता है।

DECLARE @N INT = 0

CREATE TABLE #T ( I INT );

/*Reference to #T means this statement is subject to deferred compile*/
SELECT *
FROM   master..spt_values
WHERE  number = @N
       AND EXISTS(SELECT COUNT(*) FROM #T)

SELECT *
FROM   master..spt_values
WHERE  number = @N
OPTION (RECOMPILE)

DROP TABLE #T 

आस्थगित संकलन के बावजूद चर सूँघा नहीं है और अनुमानित पंक्ति गणना गलत है

अनुमान बनाम वास्तविक

इसलिए मुझे लगता है कि धीमी योजना क्वेरी के एक मानकीकृत संस्करण से संबंधित है।

यह सभी मापदंडों के लिए ParameterCompiledValueसमान है ParameterRuntimeValue, इसलिए यह विशिष्ट पैरामीटर सूँघने के लिए नहीं है (जहाँ मूल्यों के एक सेट के लिए योजना को संकलित किया गया था, फिर मूल्यों के दूसरे सेट के लिए चलाया गया)।

समस्या यह है कि सही पैरामीटर मानों के लिए संकलित योजना अनुचित है।

आप यहाँ और यहाँ वर्णित तारीखों के साथ इस मुद्दे को मारने की संभावना है । 100 मिलियन पंक्तियों वाली तालिका के लिए आपको SQL सर्वर द्वारा स्वचालित रूप से आपके लिए आंकड़े अपडेट करने से पहले 20 मिलियन सम्मिलित करने (या अन्यथा संशोधित) करने की आवश्यकता होती है। ऐसा लगता है कि पिछली बार अपडेट की गई शून्य पंक्तियों को क्वेरी में दिनांक सीमा से मिलान किया गया था, लेकिन अब 7 मिलियन करते हैं।

आप अधिक लगातार आँकड़े अपडेट शेड्यूल कर सकते हैं, ट्रेस झंडे पर विचार 2389 - 90कर सकते हैं या इसका उपयोग कर सकते हैं, OPTIMIZE FOR UKNOWNइसलिए यह केवल datetimeकॉलम पर वर्तमान में भ्रामक आंकड़ों का उपयोग करने में सक्षम होने के बजाय अनुमानों पर वापस आता है ।

यह SQL सर्वर के अगले संस्करण (2012 के बाद) में आवश्यक नहीं हो सकता है। एक संबंधित कनेक्ट आइटम पेचीदा प्रतिक्रिया शामिल

Microsoft द्वारा 8/28/2012 को 1:35 PM पर पोस्ट किया गया है कि
हमने अगले प्रमुख रिलीज़ के लिए कार्डिनैलिटी अनुमान वृद्धि की है जो अनिवार्य रूप से इसे ठीक करता है। हमारे पूर्वावलोकन सामने आने के बाद विवरण के लिए बने रहें। एरिक

2014 के इस सुधार को बेंजामिन नेवरेज़ ने लेख के अंत में देखा है:

नए SQL सर्वर कार्डिनैलिटी एस्टीमेटर पर एक पहली नज़र

ऐसा प्रतीत होता है कि नया कार्डिनैलिटी अनुमानक वापस गिर जाएगा और 1 पंक्ति अनुमान देने के बजाय इस मामले में औसत घनत्व का उपयोग करेगा।

2014 कार्डिनैलिटी अनुमानक और आरोही प्रमुख समस्या के बारे में कुछ अतिरिक्त विवरण:

SQL सर्वर 2014 में नई कार्यक्षमता - भाग 2 - नई कार्डिनैलिटी अनुमान


29

तो, मेरा सवाल यह है ... जब हम एक खाली प्लान कैश पर समान धीमी क्वेरी प्राप्त कर सकते हैं तो स्निफिंग पैरामीटर को कैसे दोष दिया जा सकता है ... सूंघने के लिए कोई पैरामीटर नहीं होना चाहिए?

जब SQL सर्वर पैरामीटर मान वाले क्वेरी को संकलित करता है, तो यह कार्डिनैलिटी (पंक्ति गणना) अनुमान के लिए उन मापदंडों के विशिष्ट मानों को सूँघता है। आपके मामले में, के विशेष मूल्यों @BeginDate, @EndDateऔर @ClientIDजब एक कार्य योजना लागू करके चुनने किया जाता है। आप यहाँ और यहाँ सूँघने के बारे में अधिक जानकारी पा सकते हैं । मैं इन पृष्ठभूमि लिंक प्रदान कर रहा हूं क्योंकि ऊपर दिया गया सवाल मुझे लगता है कि अवधारणा को अपूर्ण रूप से वर्तमान में समझा जाता है - एक योजना संकलित होने पर हमेशा सूंघने के लिए पैरामीटर मान होते हैं।

वैसे भी, यह सब बिंदु के बगल में है, क्योंकि पैरामीटर सूँघना यहाँ समस्या नहीं है क्योंकि मार्टिन स्मिथ ने बताया है। जिस समय धीमी क्वेरी संकलित की गई थी, उस समय संकेत दिए गए आँकड़े थे कि सूँघे गए मानों के लिए कोई पंक्तियाँ नहीं थीं : @BeginDateऔर@EndDate

धीमी योजना सूँघा मूल्यों

सूँघने के मूल्य बहुत हाल के हैं, आरोही प्रमुख समस्या का सुझाव देते हुए मार्टिन उल्लेख करते हैं। क्योंकि तारीखों पर सूचकांक की तलाश के लिए सिर्फ एक पंक्ति को वापस करने का अनुमान है, ऑप्टिमाइज़र एक योजना चुनता ClientIDहै जो मुख्य लुकअप ऑपरेटर को एक अवशिष्ट के रूप में विधेय को आगे बढ़ाता है।

एकल पंक्ति का अनुमान भी कारण है कि आशावादी बेहतर योजनाओं की तलाश में रुक जाता है, एक अच्छा पर्याप्त योजना मिला संदेश लौटाता है। एकल पंक्ति अनुमान के साथ धीमी योजना की अनुमानित कुल लागत सिर्फ 0.013136 लागत इकाइयां हैं, इसलिए कुछ भी बेहतर खोजने की कोशिश नहीं है। सिवाय इसके, वास्तव में, खोज वास्तव में एक के बजाय 7,388,383 पंक्तियों को वापस करती है, जिससे कुंजी लुकअप की समान संख्या होती है।

बड़ी-बड़ी तालिकाओं पर अप-टू-डेट और उपयोगी रखने के लिए आंकड़े मुश्किल हो सकते हैं और विभाजन उस संबंध में अपनी खुद की चुनौतियों का परिचय देता है। मुझे २३ not ९ और २३ ९ ० के झंडे के साथ खुद को विशेष सफलता नहीं मिली है, लेकिन आपको उनका परीक्षण करने के लिए स्वागत है। SQL सर्वर (R2 SP1 और बाद) के अधिक हाल के बिल्ड में डायनेमिक आँकड़े अद्यतन उपलब्ध हैं, लेकिन यह प्रति-विभाजन आँकड़े अद्यतन अभी भी लागू नहीं हैं। इस बीच, जब भी आप इस तालिका में महत्वपूर्ण परिवर्तन करते हैं, तो आप मैन्युअल आँकड़े अद्यतन को शेड्यूल करना पसंद कर सकते हैं।

इस विशेष क्वेरी के लिए, मैं तेज क्वेरी योजना के संकलन के दौरान ऑप्टिमाइज़र द्वारा सुझाए गए सूचकांक को लागू करने के बारे में सोचूंगा:

/*
The Query Processor estimates that implementing the following index could improve
the query cost by 98.8091%.

WARNING: This is only an estimate, and the Query Processor is making this 
recommendation based solely upon analysis of this specific query.
It has not considered the resulting index size, or its workload-wide impact,
including its impact on INSERT, UPDATE, DELETE performance.
These factors should be taken into account before creating this index.
*/
CREATE NONCLUSTERED INDEX [<Name of Missing Index>]
ON [dbo].[PDetail] ([ClientID],[PostedDate])
INCLUDE ([Amount]);

सूचकांक को एक ON PartitionSchemeName (PostedDate)खंड के साथ विभाजन-संरेखित किया जाना चाहिए , लेकिन बिंदु यह है कि स्पष्ट रूप से सर्वोत्तम डेटा एक्सेस पथ प्रदान करने से आशावादी को खराब योजना विकल्पों से बचने में मदद मिलेगी, बिना OPTIMIZE FOR UNKNOWNसंकेत या पुराने ढंग के वर्कअराउंड जैसे स्थानीय चर का उपयोग करने के बिना ।

सुधार किए गए सूचकांक के साथ, Amountकॉलम को पुनः प्राप्त करने के लिए कुंजी लुकअप को समाप्त कर दिया जाएगा, क्वेरी प्रोसेसर अभी भी गतिशील विभाजन उन्मूलन कर सकता है, और किसी विशेष ClientIDऔर तिथि सीमा को खोजने के लिए उपयोग कर सकता है ।


काश मैं दो उत्तरों को सही मान सकता, लेकिन फिर से, अतिरिक्त जानकारी के लिए धन्यवाद - बहुत शिक्षाप्रद।
RThomas

1
मुझे पोस्ट किए हुए कुछ साल हो गए हैं ... लेकिन मैं आपको बताना चाहता था। मैं अभी भी सभी अपूर्ण समय के लिए "अपूर्ण रूप से समझा गया" शब्द का उपयोग करता हूं, और मैं हमेशा पॉल व्हाइट के बारे में सोचता हूं जब मैं करता हूं। मुझे हर बार चकल्लस करता है।
RTHomas

0

मुझे ठीक वही समस्या थी जहां एक संग्रहीत प्रक्रिया धीमी हो गई थी, OPTIMIZE FOR UNKNOWNऔर RECOMPILEक्वेरी के संकेत ने धीमापन को हल कर दिया और निष्पादन समय को बढ़ा दिया। हालाँकि, निम्न दो विधियाँ संग्रहीत कार्यविधि की सुस्ती को प्रभावित नहीं करती हैं: (i) RECOMPILE का उपयोग करके कैश (ii) को साफ़ करना। तो, जैसा आपने कहा, यह वास्तव में सूँघने का पैरामीटर नहीं था।

ट्रेस झंडे 2389 और 2390 ने भी मदद नहीं की। केवल आँकड़ों को अपडेट करते हुए ( EXEC sp_updatestats) मेरे लिए किया।

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