दूसरा INSERT
कथन ~ 5x पहले की तुलना में धीमा क्यों है ?
उत्पन्न लॉग डेटा की मात्रा से, मुझे लगता है कि दूसरा न्यूनतम लॉगिंग के लिए योग्य नहीं है। हालाँकि, डेटा लोड हो रहा है प्रदर्शन गाइड में प्रलेखन इंगित करता है कि दोनों आवेषण न्यूनतम लॉग इन करने में सक्षम होना चाहिए। इसलिए यदि न्यूनतम लॉगिंग महत्वपूर्ण प्रदर्शन अंतर है, तो ऐसा क्यों है कि दूसरी क्वेरी न्यूनतम लॉगिंग के लिए योग्य नहीं है? स्थिति को सुधारने के लिए क्या किया जा सकता है?
# 1 क्वेरी: INSERT का उपयोग करके 5MM पंक्तियों को सम्मिलित करना ... (TABLOCK) के साथ
निम्नलिखित क्वेरी पर विचार करें, जो 5MM पंक्तियों को एक ढेर में सम्मिलित करता है। जैसा कि रिपोर्ट किया गया है, यह क्वेरी लेन-देन और लॉग डेटा 1 second
उत्पन्न करती 64MB
है sys.dm_tran_database_transactions
।
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that correctly estimates that it will generate 5MM rows
FROM dbo.fiveMillionNumbers
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
# 2 क्वेरी: समान डेटा सम्मिलित करता है, लेकिन SQL पंक्तियों के # को कम करके आंका जाता है
अब इस समान क्वेरी पर विचार करें, जो बिल्कुल उसी डेटा पर संचालित होती है, लेकिन एक तालिका (या SELECT
मेरे वास्तविक उत्पादन मामले में कई जोड़ के साथ जटिल विवरण) से आरेखित होती है जहां कार्डिनिटी का अनुमान बहुत कम है। यह क्वेरी लेन-देन लॉग डेटा में निष्पादित 5.5 seconds
और उत्पन्न होती 461MB
है।
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that produces 5MM rows but SQL estimates just 1000 rows
FROM dbo.fiveMillionNumbersBadEstimate
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
पूरी स्क्रिप्ट
परीक्षण डेटा उत्पन्न करने और इनमें से किसी भी परिदृश्य को निष्पादित करने के लिए स्क्रिप्ट के पूरे सेट के लिए इस पास्टबिन को देखें । ध्यान दें कि आपको SIMPLE
पुनर्प्राप्ति मॉडल में एक डेटाबेस का उपयोग करना चाहिए ।
व्यावसायिक संदर्भ
हम अर्ध-अक्सर डेटा की लाखों पंक्तियों के चारों ओर घूम रहे हैं, और इन ऑपरेशनों को यथासंभव प्रभावी होना आवश्यक है, निष्पादन समय और डिस्क I / O लोड दोनों के संदर्भ में। हम शुरू में इस धारणा के तहत थे कि एक ढेर तालिका बनाना और उपयोग INSERT...WITH (TABLOCK)
करना ऐसा करने का एक अच्छा तरीका था, लेकिन अब यह देखते हुए कम आत्मविश्वास हो गया है कि हमने वास्तविक उत्पादन परिदृश्य में ऊपर प्रदर्शित स्थिति का अवलोकन किया है (अधिक जटिल प्रश्नों के साथ, न कि सरलीकृत संस्करण यहाँ)।
SELECT
कई जोड़ों के साथ एक जटिल कथन होता है जो परिणाम के लिए सेट उत्पन्न करता हैINSERT
। ये अंतिम तालिका सम्मिलित करने वाले ऑपरेटर के लिए खराब कार्डिनैलिटी अनुमानों का उत्पादन करते हैं (जिसे मैंने खराबUPDATE STATISTICS
कॉल के माध्यम से रिप्रो स्क्रिप्ट में सिम्युलेटेड किया है ), और इसलिए यहUPDATE STATISTICS
समस्या को ठीक करने के लिए आदेश जारी करने के रूप में काफी सरल नहीं है। मैं इस बात से पूरी तरह सहमत हूँ कि क्वेरी को सरल बनाना ताकि कार्डिनैलिटी एस्टिमेटर को समझना आसान हो, एक अच्छा दृष्टिकोण हो सकता है, लेकिन यह दिए गए जटिल व्यावसायिक तर्क को लागू करने के लिए एक बढ़िया नहीं है।