मेरे पास एक क्वेरी है जो SQL Server 2012 में 800 मिलीसेकंड में चलती है और SQL सर्वर 2014 में लगभग 170 सेकंड लगती है । मुझे लगता है कि मैंने इसे Row Count Spool
ऑपरेटर के लिए एक खराब कार्डिनैलिटी अनुमान से कम कर दिया है । मैंने स्पूल ऑपरेटरों (जैसे, यहाँ और यहाँ ) के बारे में थोड़ा पढ़ा है , लेकिन मुझे अभी भी कुछ चीजों को समझने में परेशानी हो रही है:
- इस क्वेरी को
Row Count Spool
ऑपरेटर की आवश्यकता क्यों है ? मुझे नहीं लगता कि यह शुद्धता के लिए आवश्यक है, इसलिए यह किस विशिष्ट अनुकूलन को प्रदान करने की कोशिश कर रहा है? - SQL सर्वर का अनुमान क्यों है कि
Row Count Spool
ऑपरेटर से जुड़ने से सभी पंक्तियों को हटा दिया जाता है? - यह SQL Server 2014 में एक बग है? यदि हां, तो मैं कनेक्ट में फ़ाइल करूँगा। लेकिन मैं पहले एक गहरी समझ चाहता हूं।
नोट: मैं क्वेरी को फिर से लिख सकता हूं LEFT JOIN
या SQL Server 2012 और SQL Server 2014 दोनों में स्वीकार्य प्रदर्शन प्राप्त करने के लिए तालिकाओं में अनुक्रमणिका जोड़ सकता हूं । इसलिए यह प्रश्न इस विशिष्ट क्वेरी को समझने और योजना के बारे में अधिक गहराई से और कम के बारे में है। क्वेरी को अलग तरीके से कैसे वाक्यांशित करें।
धीमी क्वेरी
पूर्ण परीक्षण स्क्रिप्ट के लिए इस पास्टबिन को देखें । यहाँ मैं देख रहा हूँ विशिष्ट परीक्षण क्वेरी है:
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
SELECT cust_nbr
FROM #existingCustomers -- 1MM rows
)
SQL सर्वर 2014: अनुमानित क्वेरी योजना
एसक्यूएल सर्वर का मानना है कि Left Anti Semi Join
करने के लिए Row Count Spool
10,000 पंक्तियों 1 पंक्ति पर नीचे फिल्टर करेगा। इस कारण से, यह LOOP JOIN
बाद में शामिल होने के लिए चयन करता है #existingCustomers
।
SQL सर्वर 2014: वास्तविक क्वेरी योजना
जैसा कि अपेक्षित था (हर कोई लेकिन SQL सर्वर!), Row Count Spool
किसी भी पंक्तियों को नहीं हटाता था। इसलिए हम 10,000 बार लूप कर रहे हैं जब SQL सर्वर सिर्फ एक बार लूप की उम्मीद करता है।
SQL सर्वर 2012: अनुमानित क्वेरी योजना
SQL सर्वर 2012 (या OPTION (QUERYTRACEON 9481)
SQL सर्वर 2014) का उपयोग करते समय, Row Count Spool
पंक्तियों के अनुमानित # को कम नहीं करता है और एक हैश ज्वाइन चुना जाता है, जिसके परिणामस्वरूप एक बेहतर योजना बनती है।
बाईं ओर फिर से लिखें
संदर्भ के लिए, यहां एक तरीका है कि मैं सभी SQL सर्वर 2012, 2014 और 2016 में अच्छा प्रदर्शन प्राप्त करने के लिए क्वेरी को फिर से लिख सकता हूं। हालांकि, मैं अभी भी ऊपर दिए गए क्वेरी के विशिष्ट व्यवहार में रुचि रखता हूं और चाहे नए SQL Server 2014 कार्डिनैलिटी एस्टीमेटर में एक बग है।
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULL