ऑपरेटर अनुमानों को बेहतर बनाने के लिए क्वेरी बदलें


14

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

मैं जिस ऑपरेशन को बेहतर बनाने की कोशिश कर रहा हूं, वह नोड 17 से योजना के दाईं ओर "इंडेक्स सीक" है।

यहाँ छवि विवरण दर्ज करें

मैंने उपयुक्त इंडेक्स जोड़े हैं, लेकिन उस ऑपरेशन के लिए मुझे जो अनुमान मिलते हैं, वे आधे हैं जो वे होने वाले हैं।

मैंने अपनी अनुक्रमणिका बदलने और एक अस्थायी तालिका जोड़ने और क्वेरी को फिर से लिखने के लिए देखा है, लेकिन सही अनुमान प्राप्त करने के लिए मैं इसे इससे अधिक सरल नहीं बना सका।

क्या किसी के पास कोई सुझाव है जो मैं कोशिश कर सकता हूं?

पूरी योजना और इसके विवरण यहां देखे जा सकते हैं

गैर-अनाम योजना यहां पाई जा सकती है।

अपडेट करें:

मुझे लगता है कि प्रश्न के प्रारंभिक संस्करण ने बहुत भ्रम पैदा किया है, इसलिए मैं कुछ स्पष्टीकरण के साथ मूल कोड जोड़ने जा रहा हूं।

create procedure [dbo].[someProcedure] @asType int, @customAttrValIds idlist readonly
as
begin
    set nocount on;

    declare @dist_ca_id int;

    select *
    into #temp
    from @customAttrValIds
        where id is not null;

    select @dist_ca_id = count(distinct CustomAttrID) 
    from CustomAttributeValues c
        inner join #temp a on c.Id = a.id;

    select a.Id
        , a.AssortmentId 
    from Assortments a
        inner join AssortmentCustomAttributeValues acav
            on a.Id = acav.Assortment_Id
        inner join CustomAttributeValues cav 
            on cav.Id = acav.CustomAttributeValue_Id
    where a.AssortmentType = @asType
        and acav.CustomAttributeValue_Id in (select id from #temp)
    group by a.AssortmentId
        , a.Id
    having count(distinct cav.CustomAttrID) = @dist_ca_id
    option(recompile);

end

उत्तर:

  1. क्यों पेस्ट में अजीब प्रारंभिक नामकरण। लिंक लिंक?

    उत्तर : क्योंकि मैंने SQL संतरी प्लान एक्सप्लोरर से अनाम योजना का उपयोग किया था।

  2. क्यों OPTION RECOMPILE?

    उत्तर : क्योंकि मैं पैरामीटर सूँघने से बचने के लिए recompiles बर्दाश्त कर सकता हूं (डेटा तिरछा है / हो सकता है)। मैंने परीक्षण किया है और मैं उस योजना से खुश हूं जो ऑप्टिमाइज़र उपयोग करते समय उत्पन्न करता है OPTION RECOMPILE

  3. WITH SCHEMABINDING?

    उत्तर : मैं वास्तव में इससे बचना चाहता हूं और इसका उपयोग केवल तभी करूंगा जब मेरे पास अनुक्रमित दृश्य होगा। वैसे भी, यह एक सिस्टम फ़ंक्शन ( COUNT()) है, इसलिए यहां कोई उपयोग नहीं SCHEMABINDINGहै।

अधिक संभावित सवालों के जवाब:

  1. मैं क्यों उपयोग INSERT INTO #temp FROM @customAttrributeValuesकरूं?

    उत्तर : क्योंकि मैंने देखा और अब यह जानता हूं कि जब चर का उपयोग किसी क्वेरी में प्लग किया जाता है, तो किसी भी अनुमान जो कि एक वैरिएबल के साथ काम कर रहा है, वह हमेशा 1. होता है और मैंने डेटा को एक टेम्‍प टेबल में रखने का परीक्षण किया और अनुमानित तब वास्तविक पंक्तियों के बराबर है। ।

  2. मैंने उपयोग क्यों किया and acav.CustomAttributeValue_Id in (select id from #temp)?

    उत्तर : मैं इसे #temp पर एक JOIN के साथ बदल सकता था, लेकिन डेवलपर्स बहुत भ्रमित थे और इस INविकल्प का लाभ उठाया । मुझे नहीं लगता कि जगह बदलने से कोई फर्क पड़ेगा और किसी भी तरह से, इससे कोई समस्या नहीं है।


मुझे लगता है कि #tempनिर्माण और उपयोग प्रदर्शन के लिए एक समस्या होगी, लाभ नहीं। आप केवल एक बार उपयोग की जाने वाली अन-इंडेक्स तालिका में बचत कर रहे हैं। इसे पूरी तरह से हटाने की कोशिश करें (और संभवतः इसे in (select id from #temp)एक exists
उपश्रेणी में

@ ypercube y सच है, बस कुछ ही कम पृष्ठों के बारे में एक अस्थायी तालिका के बजाय चर का उपयोग करने के साथ पढ़ा।
राडू घोरघिउ

वैसे, विकल्प (रिकॉम्पाइल) के साथ उपयोग किए जाने पर एक टेबल चर सही पंक्ति गणना अनुमान प्रदान करेगा - लेकिन अभी भी दानेदार आँकड़े, कार्डिनैलिटी आदि नहीं हैं
TH

@ ठीक है, मैंने अनुमानों पर वास्तविक निष्पादन योजना में देखा था, जब select id from @customAttrValIdsइसके बजाय select id from #tempऔर पंक्तियों की अनुमानित संख्या का उपयोग 1चर के लिए था और 3# टैम्प के लिए (जो वास्तविक # पंक्तियों के मेल खाता था)। इसलिए मैंने @साथ दिया #। और मैं क्या , जहां वे ने कहा कि जब एक tbl चर का उपयोग कर के अनुमान हमेशा 1. हो जाएगा और एक सुधार के रूप में बेहतर अनुमान है कि वे एक अस्थायी तालिका का प्रयोग करेंगे प्राप्त करने के लिए (ब्रेंट हे या हारून बर्ट्रेंड से) एक बात याद है।
रादु घोरघिउ

@RaduGheorghiu हाँ, लेकिन उन लोगों की दुनिया में, विकल्प (recompile) शायद ही कभी एक विकल्प होता है, और वे अन्य वैध कारणों के लिए अस्थायी तालिकाओं को भी प्राथमिकता देते हैं। हो सकता है कि अनुमान हमेशा गलत तरीके से 1 के रूप में दिखाता हो, क्योंकि यह यहां देखे गए प्लान को बदल देता है: theboreddba.com/Categories/FunWithFlags/…
TH

जवाबों:


12

योजना SQL Server 2008 R2 RTM उदाहरण (10.50.1600 का निर्माण) पर संकलित की गई थी। आपको सर्विस पैक 3 (10.50.6000 का निर्माण) स्थापित करना चाहिए , इसके बाद नवीनतम पैच के साथ इसे (वर्तमान) नवीनतम बिल्ड 10.50.6542 तक लाना होगा। यह कई कारणों से महत्वपूर्ण है, जिसमें सुरक्षा, बग फिक्स और नई सुविधाएँ शामिल हैं।

पैरामीटर एंबेडिंग ऑप्टिमाइज़ेशन

वर्तमान प्रश्न के लिए, SQL Server 2008 R2 RTM ने पैरामीटर एंबेडिंग ऑप्टिमाइज़ेशन (PEO) के लिए समर्थन नहीं किया OPTION (RECOMPILE)। अभी, आप मुख्य लाभों में से एक को साकार किए बिना recompiles की लागत का भुगतान कर रहे हैं।

जब PEO उपलब्ध होता है, तो SQL सर्वर क्वेरी प्लान में सीधे स्थानीय चर और मापदंडों में संग्रहीत शाब्दिक मूल्यों का उपयोग कर सकता है। इससे नाटकीय सरलीकरण हो सकता है और प्रदर्शन बढ़ सकता है। मेरे लेख में, Parameter Sniffing, एम्बेडिंग और RECOMPILE विकल्प के बारे में अधिक जानकारी है ।

हैश, सॉर्ट और एक्सचेंज फैल

ये केवल निष्पादन योजनाओं में प्रदर्शित होते हैं जब क्वेरी SQL Server 2012 या बाद में संकलित की गई थी। पहले के संस्करणों में, हमें स्पिल के लिए निगरानी करनी थी, जबकि क्वेरी Profiler या विस्तारित ईवेंट का उपयोग करके निष्पादित कर रहा था। स्पिल्स में हमेशा शारीरिक I / O (और से) लगातार स्टोरेज टेम्पर्ड बीपी का परिणाम होता है, जिसके महत्वपूर्ण प्रदर्शन परिणाम हो सकते हैं, खासकर यदि स्पिल बड़ी है, या I / O पथ दबाव में है।

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

प्लान में एक हैश मैच (इनर जॉइन) ऑपरेटर भी है। हैश तालिका के लिए आरक्षित मेमोरी जांच पक्ष इनपुट पंक्तियों के लिए अनुमान पर आधारित है । जांच इनपुट में 847,399 पंक्तियों का अनुमान है, लेकिन 1,223,636 रन टाइम पर सामने आई हैं। यह अतिरिक्त हैश स्पिल का कारण भी हो सकता है।

निरर्थक सकल

नोड 8 पर हैश मैच (एग्रीगेट) एक ग्रुपिंग ऑपरेशन करता है (Assortment_Id, CustomAttrID), लेकिन इनपुट पंक्तियाँ आउटपुट पंक्तियों के बराबर होती हैं:

नोड 8 हैश मैच (अलग)

इससे पता चलता है कि स्तंभ संयोजन एक कुंजी है (इसलिए समूहीकरण शब्दार्थ रूप से अनावश्यक है)। निरर्थक एकत्रीकरण के प्रदर्शन की लागत में हैश विभाजन एक्सचेंजों में दो बार 1.4 मिलियन पंक्तियों को पारित करने की आवश्यकता होती है (दोनों तरफ समानांतरवाद ऑपरेटर)।

यह देखते हुए कि शामिल किए गए कॉलम अलग-अलग तालिकाओं से आते हैं, आशावादी को इस विशिष्टता की जानकारी के लिए सामान्य से अधिक कठिन है, इसलिए यह अनावश्यक समूह संचालन और अनावश्यक आदान-प्रदान से बच सकता है।

अकुशल धागा वितरण

जैसा कि जो ओबिश के जवाब में बताया गया है , नोड 14 में एक्सचेंज थ्रेड्स के बीच पंक्तियों को वितरित करने के लिए हैश विभाजन का उपयोग करता है। दुर्भाग्य से, छोटी संख्या में पंक्तियों और उपलब्ध अनुसूचियों का मतलब है कि सभी तीन पंक्तियाँ एक ही धागे पर समाप्त होती हैं। जाहिरा तौर पर समानांतर योजना धारा 9 पर एक्सचेंज के रूप में दूर तक (समानांतर ओवरहेड के साथ) चलती है।

आप इसे संबोधित कर सकते हैं (राउंड-रोबिन या ब्रॉडकास्टिंग विभाजन प्राप्त करने के लिए) नोड 13 पर डिस्टि्रक्ट सॉर्ट को समाप्त करके। सबसे आसान तरीका यह है कि #tempटेबल पर एक संकुल प्राथमिक कुंजी बनाएं , और टेबल को लोड करते समय अलग ऑपरेशन करें:

CREATE TABLE #Temp
(
    id integer NOT NULL PRIMARY KEY CLUSTERED
);

INSERT #Temp
(
    id
)
SELECT DISTINCT
    CAV.id
FROM @customAttrValIds AS CAV
WHERE
    CAV.id IS NOT NULL;

अस्थायी तालिका आँकड़े कैशिंग

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

इससे बचने के लिए, अस्थायी तालिका के आबाद होने के बाद OPTION (RECOMPILE)एक स्पष्ट के साथ एक साथ उपयोग करें UPDATE STATISTICS #TempTable, और इससे पहले कि यह एक क्वेरी में संदर्भित हो।

क्वेरी फिर से लिखना

यह हिस्सा मानता है कि #Tempतालिका के निर्माण में परिवर्तन पहले ही किए जा चुके हैं।

संभावित हैश स्पिल की लागत और निरर्थक एकत्रीकरण (और आसपास के आदान-प्रदान) को देखते हुए, यह नोड 10 पर सेट को भौतिक बनाने के लिए भुगतान कर सकता है:

CREATE TABLE #Temp2
(
    CustomAttrID integer NOT NULL,
    Assortment_Id integer NOT NULL,
);

INSERT #Temp2
(
    Assortment_Id,
    CustomAttrID
)
SELECT
    ACAV.Assortment_Id,
    CAV.CustomAttrID
FROM #temp AS T
JOIN dbo.CustomAttributeValues AS CAV
    ON CAV.Id = T.id
JOIN dbo.AssortmentCustomAttributeValues AS ACAV
    ON T.id = ACAV.CustomAttributeValue_Id;

ALTER TABLE #Temp2
ADD CONSTRAINT PK_#Temp2_Assortment_Id_CustomAttrID
PRIMARY KEY CLUSTERED (Assortment_Id, CustomAttrID);

PRIMARY KEYएक अलग चरण में जोड़ा जाता है सूचकांक का निर्माण सुनिश्चित करने के लिए सही प्रमुखता जानकारी है, और इस मुद्दे को कैशिंग अस्थायी तालिका आंकड़ों से बचने के लिए।

यदि स्मृति में पर्याप्त मेमोरी उपलब्ध है, तो यह भौतिककरण मेमोरी में होने की संभावना है ( टेम्पर्ड I / O से बचना )। SQL सर्वर 2012 (SP1 CU10 / SP2 CU1 या बाद के) में अपग्रेड करने के बाद यह और भी अधिक होने की संभावना है, जिससे ईगर राइट व्यवहार में सुधार हुआ है

यह क्रिया मध्यवर्ती सेट पर ऑप्टिमाइज़र को सटीक कार्डिनैलिटी की जानकारी देती है, इससे आंकड़े बनाने की अनुमति मिलती है, और हमें (Assortment_Id, CustomAttrID)एक कुंजी के रूप में घोषित करने की अनुमति मिलती है ।

आबादी की योजना #Temp2इस तरह दिखनी चाहिए (ध्यान दें #Temp, बिना डिस्टिंक्ट सॉर्ट के क्लस्टर इंडेक्स स्कैन , और एक्सचेंज अब राउंड-रॉबिन पंक्ति विभाजन का उपयोग करता है):

# Temp2 आबादी

उपलब्ध सेट के साथ, अंतिम क्वेरी बन जाती है:

SELECT
    A.Id,
    A.AssortmentId
FROM
(
    SELECT
        T.Assortment_Id
    FROM #Temp2 AS T
    GROUP BY
        T.Assortment_Id
    HAVING
        COUNT_BIG(DISTINCT T.CustomAttrID) = @dist_ca_id
) AS DT
JOIN dbo.Assortments AS A
    ON A.Id = DT.Assortment_Id
WHERE
    A.AssortmentType = @asType
OPTION (RECOMPILE);

हम मैन्युअल COUNT_BIG(DISTINCT...रूप से एक सरल के रूप में फिर से लिख सकते हैं COUNT_BIG(*), लेकिन नई महत्वपूर्ण जानकारी के साथ, अनुकूलक हमारे लिए ऐसा करता है:

अंतिम योजना

अंतिम योजना उस डेटा के बारे में सांख्यिकीय जानकारी के आधार पर एक लूप / हैश / मर्ज जॉइन का उपयोग कर सकती है, जिसकी मुझे एक्सेस नहीं है। एक अन्य छोटा नोट: मैंने मान लिया है कि एक सूचकांक CREATE [UNIQUE?] NONCLUSTERED INDEX IX_ ON dbo.Assortments (AssortmentType, Id, AssortmentId);मौजूद है।

वैसे भी, अंतिम योजनाओं के बारे में महत्वपूर्ण बात यह है कि अनुमान बहुत बेहतर होना चाहिए, और समूहीकरण संचालन के जटिल अनुक्रम को एक सिंगल स्ट्रीम एग्रीगेट में घटा दिया गया है (जिसमें मेमोरी की आवश्यकता नहीं है और इसलिए डिस्क को फैल नहीं सकता है)।

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


9

आपकी क्वेरी पर कार्डिनैलिटी का अनुमान वास्तव में बहुत अच्छा है। वास्तविक पंक्तियों की संख्या से बिल्कुल मेल खाने के लिए अनुमानित पंक्तियों की संख्या प्राप्त करना दुर्लभ है, खासकर जब आपके पास यह कई जोड़ हैं। आशावादी के लिए सही होने के लिए कार्डिनैलिटी के अनुमानों को जोड़ देना मुश्किल है। एक महत्वपूर्ण बात यह है कि नेस्टेड लूप के आंतरिक भाग के लिए अनुमानित पंक्तियों की संख्या उस लूप के निष्पादन के अनुसार है। इसलिए जब SQL सर्वर कहता है कि 463869 पंक्तियों को सूचकांक के साथ लाया जाएगा, तो वास्तविक अनुमान इस मामले में क्रियान्वितियों की संख्या (2) * 463869 = 927738 है जो कि वास्तविक संख्या पंक्तियों, 1360608 से दूर नहीं है। आश्चर्यजनक रूप से, नोड लूप में नोड आईडी 10 में शामिल होने के तुरंत बाद अनुमानित पंक्तियों की संख्या एकदम सही है।

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

प्रदर्शन में सुधार के संदर्भ में, जो बात मेरे सामने है, वह यह है कि एसक्यूएल सर्वर समानांतर पंक्तियों को वितरित करने के लिए हैशिंग एल्गोरिथ्म का उपयोग कर रहा है, जिसके परिणामस्वरूप उन सभी को एक ही धागे पर रखा जा रहा है:

धागा असंतुलन

परिणामस्वरूप, एक धागा सूचकांक की तलाश में सभी काम करता है:

धागा असंतुलन की तलाश

इसका मतलब है कि आपकी क्वेरी प्रभावी रूप से समानांतर में नहीं चलती है जब तक कि नोड आईडी पर ऑपरेटर धारा 9 नहीं करता है। आप जो चाहते हैं वह राउंड रॉबिन विभाजन है ताकि प्रत्येक पंक्ति अपने स्वयं के धागे पर समाप्त हो जाए। यह नोड थ्रेड 17 के लिए अनुक्रमणिका की तलाश में दो थ्रेड्स करने की अनुमति देगा। एक शानदार TOPऑपरेटर को जोड़ने से आपको राउंड रॉबिन विभाजन मिल सकता है। यदि आप चाहें तो मैं यहां विवरण जोड़ सकता हूं।

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

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


-2

मेरा मानना ​​है कि ज्वाइन करने पर बेहतर अनुमान लगाने से योजना में बदलाव नहीं होगा, जब तक कि आशा के लिए इंडेक्स (क्लस्टर नहीं) स्कैन के साथ 1.4 मिल एक पर्याप्त हिस्सा है, जिसमें हैश या मर्ज ज्वाइन का इंडेक्स नहीं है। मुझे लगता है कि मामला यहाँ नहीं होगा, और न ही वास्तव में उपयोगी है, लेकिन आप की जगह प्रभाव का परीक्षण कर सकते भीतरी में शामिल होने के साथ CustomAttributeValues के खिलाफ आंतरिक हैश में शामिल होने और भीतरी मर्ज में शामिल होने के

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


3
उस क्वेरी के लिए योजनाओं का एक बहुत बड़ा स्थान है, जिसमें शामिल होने के आदेश और घोंसले के शिकार, समानता, स्थानीय / वैश्विक एकत्रीकरण आदि के लिए कई विकल्प हैं, जिनमें से अधिकांश व्युत्पन्न आंकड़ों (वितरण के साथ-साथ कच्ची कार्डिनैलिटी) में परिवर्तन से प्रभावित होंगे। नोड १. योजना १० पर। ध्यान दें कि संकेत शामिल होने से आमतौर पर बचना चाहिए, क्योंकि वे एक मूक के साथ आते हैं OPTION(FORCE ORDER), जो ऑप्टिमाइज़र को पुन: क्रमबद्ध पाठ अनुक्रम से जुड़ने से रोकता है, और इसके अलावा कई अन्य अनुकूलन।
पॉल व्हाइट 9

-12

आप एक [गैर-संकुल] इंडेक्स सीक से सुधार नहीं करने जा रहे हैं। केवल एक गैर-संकुल सूचकांक की तुलना में बेहतर चीज एक क्लस्टर सूचकांक की तलाश है।

इसके अलावा, मैं पिछले दस वर्षों से SQL DBA, और उससे पहले पाँच वर्षों के लिए SQL डेवलपर रहा हूँ, और मेरे अनुभव में निष्पादन योजना का अध्ययन करके SQL क्वेरी में सुधार खोजना बेहद दुर्लभ है, जिसे आप ' t अन्य साधनों द्वारा खोजें। निष्पादन योजना उत्पन्न करने का मुख्य कारण यह है कि यह अक्सर आपके लिए अनुपलब्ध अनुक्रमणिका सुझाएगा जिसे आप प्रदर्शन में सुधार करने के लिए जोड़ सकते हैं।

मुख्य प्रदर्शन लाभ एसक्यूएल क्वेरी को स्वयं समायोजित करने में होगा, अगर वहां कोई अक्षमता हो। उदाहरण के लिए, कुछ महीने पहले मुझे SELECT UNION SELECTमानक SQL PIVOTऑपरेटर का उपयोग करने के लिए स्टाइल पिवट टेबल को फिर से लिखकर 160 बार तेजी से चलाने के लिए एक SQL फ़ंक्शन मिला ।

insert into Variable1 values (?), (?), (?)


select *
    into Object1
    from Variable2
        where Column1 is not null;



select Variable3 = Function1(distinct Column2) 
    from Object2 Object3
        inner join Object1 Object4 on Object3.Column1 = Object4.Column1;



select Object4.Column1
        , Object4.Column3 
    from Object5 Object4
        inner join Object6 Object7
            on Object4.Column1 = Object7.Column4
        inner join Object2 Object8 
            on Object8.Column1 = Object7.Column5
    where Object4.Column6 = Variable4
        and Object7.Column5 in (select Column1 from Object1)
    group by Object4.Column3
        , Object4.Column1
    having Function1(distinct Object8.Column2) = Variable3
    option(recompile);

तो चलो देखते हैं, SELECT * INTOआम तौर पर एक मानक से कम कुशल है INSERT Object1 (column list) SELECT column list। इसलिए मैं फिर से लिखूंगा। अगला, यदि फ़ंक्शन 1 को ए के बिना परिभाषित किया गया था, तो WITH SCHEMABINDINGएक WITH SCHEMABINDINGखंड जोड़कर इसे तेजी से चलाने की अनुमति देनी चाहिए।

आपने बहुत सारे उपनाम चुने हैं जो समझ में नहीं आते हैं, जैसे ऑब्जेक्ट 2 को ऑब्जेक्ट 3 के रूप में अलियासिंग करना। आपको बेहतर उपनाम चुनना चाहिए जो कोड को बाधित न करें। आपके पास "Object7.Column5 in (ऑब्जेक्ट 1 से कॉलम 1 चुनें)" है।

INइस प्रकृति के खंड हमेशा अधिक कुशल लिखे जाते हैं EXISTS (SELECT 1 FROM Object1 o1 WHERE o1.Column1 = Object7.Column5)। शायद मुझे लिखा जाना चाहिए था कि दूसरा तरीका। EXISTSहमेशा कम से कम जितना अच्छा होगा IN। यह हमेशा बेहतर नहीं है, लेकिन आमतौर पर है।

इसके अलावा, मुझे संदेह है कि option(recompile)यहां क्वेरी प्रदर्शन में सुधार हो रहा है । मैं इसे हटाने का परीक्षण करूंगा।


6
यदि कोई गैर-अनुक्रमित अनुक्रमणिका खोज क्वेरी को कवर करती है, तो यह लगभग हमेशा क्लस्टर इंडेक्स की तुलना में बेहतर होने वाली होती है, क्योंकि परिभाषा के अनुसार, क्लस्टर्ड इंडेक्स में सभी कॉलम होते हैं, और गैर-अनुक्रमित इंडेक्स में कम कॉलम होते हैं, इस तरह से कम समय की आवश्यकता होती है (और डेटा को पुनः प्राप्त करने के लिए बी-ट्री में कम स्तर)। इसलिए यह कहना सही नहीं है कि क्लस्टर इंडेक्स की तलाश हमेशा बेहतर होगी ।
3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.