योजना 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)
, लेकिन इनपुट पंक्तियाँ आउटपुट पंक्तियों के बराबर होती हैं:
इससे पता चलता है कि स्तंभ संयोजन एक कुंजी है (इसलिए समूहीकरण शब्दार्थ रूप से अनावश्यक है)। निरर्थक एकत्रीकरण के प्रदर्शन की लागत में हैश विभाजन एक्सचेंजों में दो बार 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
, बिना डिस्टिंक्ट सॉर्ट के क्लस्टर इंडेक्स स्कैन , और एक्सचेंज अब राउंड-रॉबिन पंक्ति विभाजन का उपयोग करता है):
उपलब्ध सेट के साथ, अंतिम क्वेरी बन जाती है:
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);
मौजूद है।
वैसे भी, अंतिम योजनाओं के बारे में महत्वपूर्ण बात यह है कि अनुमान बहुत बेहतर होना चाहिए, और समूहीकरण संचालन के जटिल अनुक्रम को एक सिंगल स्ट्रीम एग्रीगेट में घटा दिया गया है (जिसमें मेमोरी की आवश्यकता नहीं है और इसलिए डिस्क को फैल नहीं सकता है)।
यह कहना मुश्किल है कि अतिरिक्त अस्थायी तालिका के साथ इस मामले में प्रदर्शन वास्तव में बेहतर होगा , लेकिन अनुमान और योजना के विकल्प समय के साथ डेटा की मात्रा और वितरण में बदलाव के लिए अधिक लचीला होंगे। यह आज एक छोटे से प्रदर्शन में वृद्धि की तुलना में लंबी अवधि में अधिक मूल्यवान हो सकता है। किसी भी मामले में, आपके पास अब अधिक जानकारी है जिस पर आप अपने अंतिम निर्णय को आधार बना सकते हैं।
#temp
निर्माण और उपयोग प्रदर्शन के लिए एक समस्या होगी, लाभ नहीं। आप केवल एक बार उपयोग की जाने वाली अन-इंडेक्स तालिका में बचत कर रहे हैं। इसे पूरी तरह से हटाने की कोशिश करें (और संभवतः इसेin (select id from #temp)
एकexists