यह आपकी तालिकाओं, आपके अनुक्रमित आंकड़ों पर निर्भर करता है, .... निष्पादन योजनाओं / io + समय के आंकड़ों की तुलना किए बिना कहने में मुश्किल है।
अंतर मैं उम्मीद करूँगा कि दो टेबल के बीच जोइन से पहले अतिरिक्त फ़िल्टरिंग हो रही है। मेरे उदाहरण में, मैंने अपनी तालिकाओं का पुन: उपयोग करने के लिए चयनों के अपडेट को बदल दिया।
"अनुकूलन" के साथ निष्पादन योजना
निष्पादन योजना
आप मेरे परीक्षण डेटा में स्पष्ट रूप से एक फ़िल्टर ऑपरेशन देख रहे हैं, जहाँ कोई रिकॉर्ड नहीं है जहाँ फ़िल्टर किया गया है और परिणामस्वरूप कोई सुधार नहीं हुआ है जहाँ बनाया गया है।
"अनुकूलन" के बिना निष्पादन योजना
निष्पादन योजना
फ़िल्टर चला गया है, जिसका अर्थ है कि हमें अनावश्यक रिकॉर्ड को फ़िल्टर करने के लिए जुड़ने पर निर्भर रहना होगा।
अन्य कारण (ओं)
क्वेरी को बदलने का एक और कारण / परिणाम हो सकता है, कि क्वेरी को बदलते समय एक नई निष्पादन योजना बनाई गई थी, जो तेजी से होती है। इसका एक उदाहरण एक अलग जॉइन ऑपरेटर चुनने वाला इंजन है, लेकिन वह केवल इस बिंदु पर अनुमान लगा रहा है।
संपादित करें:
दो क्वेरी योजनाओं को प्राप्त करने के बाद स्पष्ट:
क्वेरी बड़ी तालिका से 550M पंक्तियों को पढ़ रही है, और उन्हें फ़िल्टर कर रही है।
मतलब यह है कि विधेय सबसे अधिक छानने का काम करने वाला है, न कि शोध करने वाला। डेटा में परिणाम पढ़ा जा रहा है, लेकिन जिस तरह से कम किया जा रहा है।
Sql सर्वर बनाना एक अलग इंडेक्स (क्वेरी प्लान) का उपयोग करता है / एक इंडेक्स को जोड़ने से यह हल हो सकता है।
तो ऑप्टिमाइज़ेशन क्वेरी में यह समान समस्या क्यों नहीं है?
क्योंकि एक अलग क्वेरी योजना का उपयोग किया जाता है, एक शोध के बजाय एक स्कैन के साथ।
किसी भी प्रकार की तलाश के बिना, लेकिन केवल 4M पंक्तियों के साथ काम करने के लिए वापस आ रहा है।
अगला अंतर
अद्यतन अंतर की उपेक्षा (अनुकूलित क्वेरी पर कुछ भी अपडेट नहीं किया जा रहा है) अनुकूलित क्वेरी पर एक हैश मैच का उपयोग किया जाता है:
नेस्टेड लूप के बजाय गैर-अनुकूलित पर शामिल हों:
एक नेस्टेड लूप सबसे अच्छा होता है जब एक टेबल छोटा होता है और दूसरा बड़ा। चूंकि वे दोनों एक ही आकार के करीब हैं इसलिए मैं तर्क दूंगा कि इस मामले में हैश मैच बेहतर विकल्प है।
अवलोकन
अनुकूलित क्वेरी
ऑप्टिमाइज़्ड क्वेरी की योजना में समानता है, एक हैश मैच जॉइन का उपयोग करता है, और कम अवशिष्ट IO फ़िल्टरिंग करने की आवश्यकता होती है। यह उन प्रमुख मूल्यों को समाप्त करने के लिए बिटमैप का भी उपयोग करता है जो किसी भी सम्मिलित पंक्तियों का उत्पादन नहीं कर सकते हैं। (इसके अलावा कुछ भी अपडेट नहीं किया जा रहा है)
गैर-अनुकूलित क्वेरी
गैर-ऑप्टिमाइज़्ड क्वेरी की योजना में कोई समानता नहीं है, एक नेस्टेड लूप जॉइन का उपयोग करता है, और 550M रिकॉर्ड पर अवशिष्ट IO फ़िल्टरिंग करने की आवश्यकता होती है। (अपडेट भी हो रहा है)
गैर-अनुकूलित क्वेरी को बेहतर बनाने के लिए आप क्या कर सकते हैं?
कुंजी कॉलम सूची में पहले_नाम और last_name के लिए सूचकांक को बदलना:
Dbo.largeTableOfPeople (birth_date, first_name, last_name) में शामिल करें (आईडी)
लेकिन कार्यों के उपयोग और इस तालिका के बड़े होने के कारण यह इष्टतम समाधान नहीं हो सकता है।
- आँकड़ों को अद्यतन करना, बेहतर योजना बनाने और प्राप्त करने के लिए recompile का उपयोग करना।
(HASH JOIN, MERGE JOIN)
क्वेरी में विकल्प जोड़ना
- ...
परीक्षण डेटा + क्वेरी का उपयोग किया गया
CREATE TABLE #smallTableOfPeople(importantValue int, birthDate datetime2, first_name varchar(50),last_name varchar(50));
CREATE TABLE #largeTableOfPeople(importantValue int, birth_date datetime2, first_name varchar(50),last_name varchar(50));
set nocount on;
DECLARE @i int = 1
WHILE @i <= 1000
BEGIN
insert into #smallTableOfPeople (importantValue,birthDate,first_name,last_name)
VALUES(NULL, dateadd(mi,@i,'2018-01-18 11:05:29.067'),'Frodo','Baggins');
set @i += 1;
END
set nocount on;
DECLARE @j int = 1
WHILE @j <= 20000
BEGIN
insert into #largeTableOfPeople (importantValue,birth_Date,first_name,last_name)
VALUES(@j, dateadd(mi,@j,'2018-01-18 11:05:29.067'),'Frodo','Baggins');
set @j += 1;
END
SET STATISTICS IO, TIME ON;
SELECT smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
ON largeTbl.birth_date = smallTbl.birthDate
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å');
SELECT smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
ON largeTbl.birth_date = smallTbl.birthDate
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
--AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å')
drop table #largeTableOfPeople;
drop table #smallTableOfPeople;
AND LEFT(TRIM(largeTbl.last_name), 1) BETWEEN 'a' AND 'z' COLLATE LATIN1_GENERAL_CI_AI
आपको वही करना चाहिए जो आपको सभी पात्रों की सूची की आवश्यकता के बिना करना चाहिए और कोड को पढ़ना मुश्किल है