निष्पादन योजना का उपयोग करके टी-एसक्यूएल क्वेरी का अनुकूलन कैसे करें


15

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

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

यह प्रश्न है:

DECLARE @Param0 DATETIME     = '2013-07-29';
DECLARE @Param1 INT          = CONVERT(INT, CONVERT(VARCHAR, @Param0, 112))
DECLARE @Param2 VARCHAR(50)  = 'ABC';
DECLARE @Param3 VARCHAR(100) = 'DEF';
DECLARE @Param4 VARCHAR(50)  = 'XYZ';
DECLARE @Param5 VARCHAR(100) = NULL;
DECLARE @Param6 VARCHAR(50)  = 'Text3';

SET NOCOUNT ON

DECLARE @MyTableVar TABLE
(
    B_Var1_PK int,
    Job_Var1 varchar(512),
    Job_Var2 varchar(50)
)

INSERT INTO @MyTableVar (B_Var1_PK, Job_Var1, Job_Var2) 
SELECT B_Var1_PK, Job_Var1, Job_Var2 FROM [fn_GetJobs] (@Param1, @Param2, @Param3, @Param4, @Param6);

CREATE TABLE #TempTable
(
    TTVar1_PK INT PRIMARY KEY,
    TTVar2_LK VARCHAR(100),
    TTVar3_LK VARCHAR(50),
    TTVar4_LK INT,
    TTVar5 VARCHAR(20)
);

INSERT INTO #TempTable
SELECT DISTINCT
    T.T1_PK,
    T.T1_Var1_LK,
    T.T1_Var2_LK,
    MAX(T.T1_Var3_LK),
    T.T1_Var4_LK
FROM
    MyTable1 T
    INNER JOIN feeds.MyTable2 A ON A.T2_Var1 = T.T1_Var4_LK
    INNER JOIN @MyTableVar B ON B.Job_Var2 = A.T2_Var2 AND B.Job_Var1 = A.T2_Var3
GROUP BY T.T1_PK, T.T1_Var1_LK, T.T1_Var2_LK, T.T1_Var4_LK

-- This is the slow statement...
SELECT 
    CASE E.E_Var1_LK
        WHEN 'Text1' THEN T.TTVar2_LK + '_' + F.F_Var1
        WHEN 'Text2' THEN T.TTVar2_LK + '_' + F.F_Var2
        WHEN 'Text3' THEN T.TTVar2_LK
    END,
    T.TTVar4_LK,
    T.TTVar3_LK,
    CASE E.E_Var1_LK
        WHEN 'Text1' THEN F.F_Var1
        WHEN 'Text2' THEN F.F_Var2
        WHEN 'Text3' THEN T.TTVar5
    END,
    A.A_Var3_FK_LK,
    C.C_Var1_PK,
    SUM(CONVERT(DECIMAL(18,4), A.A_Var1) + CONVERT(DECIMAL(18,4), A.A_Var2))
FROM #TempTable T
    INNER JOIN TableA (NOLOCK) A ON A.A_Var4_FK_LK  = T.TTVar1_PK
    INNER JOIN @MyTableVar     B ON B.B_Var1_PK     = A.Job
    INNER JOIN TableC (NOLOCK) C ON C.C_Var2_PK     = A.A_Var5_FK_LK
    INNER JOIN TableD (NOLOCK) D ON D.D_Var1_PK     = A.A_Var6_FK_LK
    INNER JOIN TableE (NOLOCK) E ON E.E_Var1_PK     = A.A_Var7_FK_LK  
    LEFT OUTER JOIN feeds.TableF (NOLOCK) F ON F.F_Var1 = T.TTVar5
WHERE A.A_Var8_FK_LK = @Param1
GROUP BY
    CASE E.E_Var1_LK
        WHEN 'Text1' THEN T.TTVar2_LK + '_' + F.F_Var1
        WHEN 'Text2' THEN T.TTVar2_LK + '_' + F.F_Var2
        WHEN 'Text3' THEN T.TTVar2_LK
    END,
    T.TTVar4_LK,
    T.TTVar3_LK,
    CASE E.E_Var1_LK 
        WHEN 'Text1' THEN F.F_Var1
        WHEN 'Text2' THEN F.F_Var2
        WHEN 'Text3' THEN T.TTVar5
    END,
    A.A_Var3_FK_LK, 
    C.C_Var1_PK


IF OBJECT_ID(N'tempdb..#TempTable') IS NOT NULL
BEGIN
    DROP TABLE #TempTable
END
IF OBJECT_ID(N'tempdb..#TempTable') IS NOT NULL
BEGIN
    DROP TABLE #TempTable
END

जो मैंने पाया है कि तीसरा कथन (धीमा होने के रूप में टिप्पणी की गई) वह हिस्सा है जो सबसे अधिक समय ले रहा है। लगभग तुरंत लौटने से पहले दो बयान।

निष्पादन योजना इस लिंक पर XML के रूप में उपलब्ध है ।

अपने ब्राउज़र में खोलने के बजाय SQL संतरी प्लान एक्सप्लोरर या कुछ अन्य देखने वाले सॉफ़्टवेयर में राइट-क्लिक और सेव करें और फिर खोलें।

यदि आपको टेबल या डेटा के बारे में मुझसे कोई और जानकारी चाहिए, तो कृपया पूछने में संकोच न करें।


2
आपके आंकड़े बंद हैं। आखिरी बार जब आप डी-खंडित अनुक्रमित या अपडेट किए गए आँकड़े हैं? इसके अलावा, मैं एक अस्थायी तालिका का उपयोग करने की कोशिश करूंगा, तालिका चर के बजाय, @MyTableVar, क्योंकि अनुकूलक वास्तव में तालिका चर पर आँकड़ों का उपयोग नहीं कर सकता है।
एडम हैन्स 20

आपके उत्तर के लिए धन्यवाद एडम। @MyTableVar को टेम्प टेबल में बदलने से कोई प्रभाव नहीं पड़ता है, लेकिन यह केवल छोटी संख्या में पंक्तियाँ हैं (जिन्हें निष्पादन योजना से देखा जा सकता है)। निष्पादन योजना में क्या दिखाया गया है कि मेरे आँकड़े बंद हैं? क्या यह इंगित करता है कि कौन से अनुक्रमितों को पुनर्गठित किया जाना चाहिए या फिर से बनाया जाना चाहिए, और किस तालिका में आंकड़े अपडेट होने चाहिए?
नव

3
नीचे दाईं ओर हैश बिल्ट इनपुट में अनुमानित 24,000 पंक्तियाँ हैं, लेकिन वास्तविक 3,285,620 तो अच्छी तरह से हो सकती हैं tempdb। यानी पंक्तियों के बीच के अनुमानों के बीच के जुड़ने के परिणामस्वरूप TableAऔर @MyTableVarरास्ता बंद हो जाता है। इसके अलावा, सॉर्ट में जाने वाली पंक्तियों की संख्या अनुमान से बहुत अधिक है ताकि वे अच्छी तरह से स्पिलिंग भी कर सकें।
मार्टिन स्मिथ

जवाबों:


22

मुख्य उत्तर पर जाने से पहले, दो सॉफ्टवेयर हैं जिन्हें आपको अपडेट करने की आवश्यकता है।

आवश्यक सॉफ़्टवेयर अद्यतन

पहला SQL Server है। आप SQL Server 2008 सर्विस पैक 1 (बिल्ड 2531) चला रहे हैं। आपको कम से कम वर्तमान सर्विस पैक (SQL Server 2008 सर्विस पैक 3 - 5500 का निर्माण) करने के लिए तैयार होना चाहिए। लेखन के समय SQL Server 2008 का सबसे हालिया निर्माण सर्विस पैक 3, संचयी अद्यतन 12 (5844 का निर्माण) है।

सॉफ्टवेयर का दूसरा टुकड़ा SQL संतरी योजना एक्सप्लोरर है । नवीनतम संस्करणों में महत्वपूर्ण नई विशेषताएं और सुधार हैं, जिसमें विशेषज्ञ विश्लेषण के लिए सीधे क्वेरी प्लान अपलोड करने की क्षमता भी शामिल है (XML को कहीं भी पेस्ट करने की आवश्यकता नहीं है!)

क्वेरी प्लान विश्लेषण

तालिका चर के लिए कार्डिनैलिटी का अनुमान बिल्कुल सही है, एक बयान-स्तर के लिए धन्यवाद।

तालिका चर अनुमान

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

पहले अनुमान लगाएं

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

SQL Server 2008 निष्पादन योजनाओं में इसे उजागर नहीं करता है; आप विस्तारित ईवेंट या प्रोइलर सॉर्ट चेतावनियों और हैश चेतावनियों का उपयोग करके फैल की निगरानी कर सकते हैं । निष्पादन शुरू होने से पहले कार्डिनैलिटी अनुमानों के आधार पर मेमोरी को सॉर्ट और हैश के लिए आरक्षित किया जाता है, और निष्पादन के दौरान बढ़ाया नहीं जा सकता है, भले ही आपके SQL सर्वर में कितनी अतिरिक्त मेमोरी हो। सटीक पंक्ति गणना का अनुमान इसलिए किसी भी निष्पादन योजना के लिए महत्वपूर्ण है जिसमें कार्यक्षेत्र मेमोरी खपत संचालन शामिल है।

आपकी क्वेरी को भी मानकीकृत किया गया है। आपको OPTION (RECOMPILE)क्वेरी को जोड़ने पर विचार करना चाहिए यदि विभिन्न पैरामीटर मान क्वेरी योजना को प्रभावित करते हैं। आपको शायद वैसे भी इसका उपयोग करने पर विचार करना चाहिए, इसलिए @Param1आशावादी संकलन समय पर मूल्य देख सकता है । यदि और कुछ नहीं, तो यह आशावादी को ऊपर दिखाए गए सूचकांक की तलाश के लिए अधिक उचित अनुमान लगाने में मदद कर सकता है, यह देखते हुए कि तालिका बहुत बड़ी है, और विभाजन किया गया है। यह स्थैतिक विभाजन उन्मूलन को भी सक्षम कर सकता है।

तालिका चर के बजाय एक अस्थायी तालिका के साथ फिर से क्वेरी का प्रयास करें और OPTION (RECOMPILE) । आपको पहले अस्थायी परिणाम में शामिल होने का प्रयास दूसरे अस्थायी तालिका में करना चाहिए, और बाकी क्वेरी को उसके विरुद्ध चलाना चाहिए। पंक्तियों की संख्या सभी बड़ी (3,285,620) नहीं है, इसलिए यह यथोचित त्वरित होना चाहिए। ऑप्टिमाइज़र में फिर से शामिल होने के परिणाम के लिए एक सटीक कार्डिनैलिटी अनुमान और वितरण आँकड़े होंगे। भाग्य के साथ, बाकी योजना अच्छी तरह से जगह में गिर जाएगी।

योजना में दिखाए गए गुणों से कार्य करना, भौतिकवादी क्वेरी होगी:

SELECT
    A.A_Var7_FK_LK,
    A.A_Var4_FK_LK,
    A.A_Var6_FK_LK, 
    A.A_Var5_FK_LK,
    A.A_Var1,
    A.A_Var2,
    A.A_Var3_FK_LK
INTO #AnotherTempTable
FROM @MyTableVar AS B
JOIN TableA AS A
    ON A.Job = B.B_Var1_PK
WHERE
    A_Var8_FK_LK = @Param1;

आप INSERTएक पूर्वनिर्धारित अस्थायी तालिका में भी शामिल हो सकते हैं (योजना में सही डेटा प्रकार नहीं दिखाए गए हैं, इसलिए मैं वह हिस्सा नहीं कर सकता)। नई अस्थायी तालिका संकुल और गैर-अनुक्रमित अनुक्रमित से लाभान्वित हो भी सकती है और नहीं भी।


इस गहन उत्तर के लिए बहुत बहुत धन्यवाद। क्षमा करें, उत्तर देने में एक सप्ताह का समय लगा है - मैं इस पर काम कर रहा हूं हर दिन अन्य काम के साथ प्रतिच्छेद किया जाता है। मैंने आपके सुझावों को टेबलए में शामिल होने के लिए लागू किया है #AnotherTempTable। ऐसा लगता है कि सबसे अच्छा प्रभाव पड़ा - अन्य सुझावों (@MyTableVar के लिए एक टेबल चर के बजाय एक अस्थायी तालिका का उपयोग करना, और उपयोग OPTION (RECOMPILE)करना बहुत अधिक प्रभाव या किसी पर भी नहीं था। 'बेनामी' और 'पोस्ट टू SQLPerformn.com'। SQL संतरी प्लान एक्सप्लोरर में विकल्प बहुत अच्छे हैं - मैंने अभी-अभी उनका उपयोग किया है: answer.sqlperformance.com/questions/1087
Neo

-6

मुझे लगता है कि @MyTableVar पर PK होना चाहिए और सहमत हूं कि #MyTableVar अक्सर प्रदर्शन कर रहा है (बड़ी संख्या में पंक्तियों के साथ)।

जहां खंड के भीतर की स्थिति

   WHERE A.A_Var8_FK_LK = @Param1

आंतरिक रूप से A AND'ED में शामिल होना चाहिए। यह करने के लिए मेरे अनुभव में ऑप्टिमाइज़र पर्याप्त चतुर नहीं है (क्षमा करें योजना पर ध्यान नहीं दिया गया) और यह एक बड़ा अंतर बना सकता है।

यदि वे परिवर्तन सुधार नहीं दिखाते हैं, तो मैं आगे A की एक और अस्थायी तालिका बनाऊंगा और सभी चीजें जो विवश (अच्छी तरह से?) A.A_Var8_FK_LK = @ Param1 से जुड़ती हैं यदि वह समूहीकरण आपके लिए तार्किक अर्थ बनाता है।

फिर उस ज्वाइनिंग कंडीशन के लिए उस टेम्प टेबल पर (या तो पहले या बाद में) एक क्लस्टर इंडेक्स बनाएं।

फिर उस परिणाम को कुछ तालिकाओं (F और T) के साथ जोड़ दें जो बनी हुई हैं।

बाम, जिन्हें पंक्ति अनुमान बंद होने पर बदबूदार क्वेरी योजना की आवश्यकता होती है और कभी-कभी वैसे भी आसानी से सुधारने योग्य नहीं होते हैं )। मैं मान रहा हूं कि आपके पास उचित संकेत हैं जो कि मैं पहले योजना के भीतर जांच करूंगा।

एक टेंपरेचर टेंपर्ड स्पिल दिखा सकता है जो कठोर प्रभाव हो सकता है या नहीं।

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

यदि आप इनमें से कई कर रहे हैं, तो शायद एक वाणिज्यिक अनुकूलक एक कोशिश (या परीक्षण) के लायक है और अभी भी एक अच्छा सीखने का अनुभव है।


हाँ यही है। यह सुनिश्चित करता है कि A द्वारा दी गई पंक्तियाँ बाधा द्वारा सीमित हैं। अन्यथा आशावादी पहले शामिल हो सकता है और बाद में बाधा लागू कर सकता है। मैं इससे रोजाना निपटता हूं।
क्रोकेक

4
@crokusek आप गलत हैं। SQL-Server का ऑप्टिमाइज़र प्रश्नों को जानने में बहुत अच्छा है, जब यह INNER ज्वाइन होता है तो समतुल्य (चाहे कोई शर्त WHERE या ON क्लॉज पर हो)।
ypercube y

6
आपको क्वेरी ऑप्टिमाइज़र पर पॉल व्हाइट की श्रृंखला उपयोगी मिल सकती है।
मार्टिन स्मिथ

इसकी एक भयानक आदत है। हो सकता है कि यह इस विशेष मामले के लिए होगा (जहां एक बाधा है) लेकिन मैं कई डेवलपर्स की भूमि से आ रहा हूं और जहां खंड पर स्थितियां हैं। SQL सर्वर आपके लिए जुड़ने के लिए उन्हें लगातार "स्थानांतरित" नहीं करता है
क्रोकेक

बाहरी (और सही जोड़) के लिए गलत सहमत हैं। लेकिन जब वहाँ रहे हैं केवल भीतर भाव AND'd जहां खंड और प्रत्येक शब्द मेल खाती है एक पूरी तरह से एक विशिष्ट आंतरिक शामिल होने के लिए, उस शब्द के सुरक्षित रूप से और विश्वास के एक अनुकूलन और सबसे अच्छा अभ्यास (imo) के रूप में "पर" स्थान पर ले जाया जा सकता है। चाहे वह "सच" में शामिल होने की स्थिति हो या बस एक स्थिर बाधा एक बड़े प्रदर्शन लाभ के लिए माध्यमिक हो। यह लिंक एक तुच्छ मामले के लिए है। वास्तविक जीवन में कई ऐसे स्थान होते हैं, जहां रूपांतरण () और गणित के साथ स्थितियां होती हैं और ऐसे उन्हें बेहतर उम्मीदवार बनाते हैं जिससे सर्वोत्तम प्रथाओं को प्राप्त किया जा सके।
क्रोकेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.