यह SQL सर्वर आंतरिक समस्यात्मक ऑपरेटर्स श्रृंखला का भाग है। पहली पोस्ट पढ़ने के लिए यहां क्लिक करें।
SQL सर्वर को लगभग 30 साल से अधिक हो गए हैं, और मैं SQL सर्वर के साथ लगभग लंबे समय से काम कर रहा हूं। मैंने इस अविश्वसनीय उत्पाद के वर्षों (और दशकों!) और संस्करणों में बहुत सारे बदलाव देखे हैं। इन पोस्ट में, मैं आपके साथ साझा करूँगा कि मैं SQL सर्वर की कुछ विशेषताओं या पहलुओं को कैसे देखता हूँ, कभी-कभी कुछ ऐतिहासिक परिप्रेक्ष्य के साथ।
पिछली बार, मैंने SQL सर्वर डायग्नोस्टिक्स में संभावित समस्याग्रस्त ऑपरेटर के रूप में SQL सर्वर क्वेरी प्लान में स्कैन ऑपरेशन के बारे में बात की थी। हालांकि अक्सर स्कैन का उपयोग केवल इसलिए किया जाता है क्योंकि कोई उपयोगी इंडेक्स नहीं होता है, ऐसे समय होते हैं जब स्कैन वास्तव में इंडेक्स सीक ऑपरेशन से बेहतर विकल्प होता है।
इस लेख में, मैं आपको ऑपरेटरों के एक अन्य परिवार के बारे में बताऊंगा जिसे कभी-कभी समस्याग्रस्त के रूप में देखा जाता है:हैशिंग। हैशिंग एक बहुत प्रसिद्ध डेटा प्रोसेसिंग एल्गोरिथम है जो कई दशकों से आसपास है। जब मैं पहली बार विश्वविद्यालय में कंप्यूटर विज्ञान का अध्ययन कर रहा था, तब मैंने अपनी डेटा संरचना कक्षाओं में इसका अध्ययन किया था। यदि आप हैशिंग और हैश फ़ंक्शन के बारे में पृष्ठभूमि की जानकारी चाहते हैं, तो आप विकिपीडिया पर इस लेख को देख सकते हैं। हालाँकि, SQL सर्वर ने SQL सर्वर 7 तक क्वेरी प्रोसेसिंग विकल्पों के अपने प्रदर्शनों की सूची में हैशिंग नहीं जोड़ा। (एक तरफ के रूप में, मैं उल्लेख करूँगा कि SQL सर्वर ने अपने कुछ आंतरिक खोज एल्गोरिदम में हैशिंग का उपयोग किया था। जैसा कि विकिपीडिया लेख में उल्लेख किया गया है। , हैशिंग एक निश्चित आकार के डेटा के लिए मनमाने आकार के डेटा को मैप करने के लिए एक विशेष फ़ंक्शन का उपयोग करता है। SQL ने हैशिंग को एक खोज तकनीक के रूप में उपयोग किया है ताकि प्रत्येक पृष्ठ को मनमाने आकार के डेटाबेस से मेमोरी में बफर में मैप किया जा सके, जो एक निश्चित आकार है। वास्तव में , sp_configure . के लिए एक विकल्प हुआ करता था जिसे 'हैश बकेट' कहा जाता है, जो आपको डेटाबेस पेजों के हैशिंग के लिए उपयोग की जाने वाली बकेट की संख्या को मेमोरी बफ़र्स में नियंत्रित करने की अनुमति देता है।)
हैशिंग क्या है?
हैशिंग एक खोज तकनीक है जिसके लिए डेटा को ऑर्डर करने की आवश्यकता नहीं होती है। SQL सर्वर इसका उपयोग जॉइन ऑपरेशंस, एग्रीगेशन ऑपरेशंस (DISTINCT या GROUP BY) या UNION ऑपरेशंस के लिए कर सकता है। इन तीन ऑपरेशनों में जो समानता है, वह यह है कि निष्पादन के दौरान, क्वेरी इंजन मिलान मूल्यों की तलाश में है। एक जॉइन में, हम एक टेबल (या रोसेट) में पंक्तियों को खोजना चाहते हैं, जिसमें दूसरे में पंक्तियों के साथ मेल खाने वाले मान हों। (और हाँ, मुझे उन जॉइन के बारे में पता है जो समानता के आधार पर पंक्तियों की तुलना नहीं कर रहे हैं, लेकिन वे गैर-समतुल्य इस चर्चा के लिए अप्रासंगिक हैं।) ग्रुप बाय के लिए, हम एक ही समूह में शामिल करने के लिए और यूनियन के लिए मिलान मान पाते हैं और DISTINCT, हम उन्हें बाहर करने के लिए मिलान करने वाले मानों की तलाश करते हैं। (हां, मुझे पता है कि यूनियन ऑल एक अपवाद है।)
SQL सर्वर 7 से पहले, इन ऑपरेशनों को मिलान करने वाले मानों को आसानी से खोजने का एकमात्र तरीका यह था कि यदि डेटा को सॉर्ट किया गया था। इसलिए, यदि कोई मौजूदा इंडेक्स नहीं था जो डेटा को क्रमबद्ध क्रम में बनाए रखता था, तो क्वेरी प्लान योजना में एक SORT ऑपरेशन जोड़ देगा। हैशिंग आंतरिक हैश फ़ंक्शन से समान परिणाम वाली सभी पंक्तियों को समान 'हैश बकेट' में डालकर कुशल खोज के लिए आपके डेटा को व्यवस्थित करता है।
आरेख सहित SQL सर्वर के हैश जॉइन ऑपरेशन की अधिक विस्तृत व्याख्या के लिए, SQL झोंपड़ी से इस ब्लॉग पोस्ट पर एक नज़र डालें।
एक बार हैशिंग एक विकल्प बन जाने के बाद, SQL सर्वर ने शामिल होने या एकत्रीकरण से पहले डेटा को सॉर्ट करने की संभावना को पूरी तरह से नजरअंदाज नहीं किया, लेकिन यह सिर्फ ऑप्टिमाइज़र के लिए विचार करने की संभावना बन गया। सामान्य तौर पर, हालांकि, यदि आप बिना क्रमबद्ध डेटा पर UNION में शामिल होने, एकत्र करने या निष्पादित करने का प्रयास कर रहे हैं, तो ऑप्टिमाइज़र आमतौर पर हैश ऑपरेशन का चयन करेगा। इतने सारे लोग मानते हैं कि एक योजना में एक हैश जॉइन (या अन्य हैश ऑपरेशन) का मतलब है कि आपके पास उपयुक्त इंडेक्स नहीं हैं और हैश ऑपरेशन से बचने के लिए आपको उचित इंडेक्स बनाना चाहिए।
आइए एक उदाहरण देखें। मैं पहले दो अनइंडेक्स्ड टेबल बनाऊंगा।
USE AdventureWorks2016 GO DROP TABLE IF EXISTS Details;
GO
SELECT * INTO Details FROM Sales.SalesOrderDetail;
GO
DROP TABLE IF EXISTS Headers;
GO
SELECT * INTO Headers FROM Sales.SalesOrderHeader;
GO
Now, I’ll join these two tables together and filter the rows in the Details table:
SELECT *
FROM Details d JOIN Headers h
ON d.SalesOrderID = h.SalesOrderID
WHERE SalesOrderDetailID < 100;
क्वेस्ट स्पॉटलाइट ट्यूनिंग पैक हैश जॉइन को एक समस्या के रूप में इंगित नहीं करता है। यह केवल दो टेबल स्कैन को हाइलाइट करता है।
सुझाव प्रत्येक तालिका पर एक अनुक्रमणिका बनाने की अनुशंसा करते हैं जिसमें प्रत्येक एकल गैर-कुंजी कॉलम शामिल कॉलम के रूप में शामिल होता है। मैं शायद ही कभी उन सिफारिशों को लेता हूं (जैसा कि मैंने अपनी पिछली पोस्ट में उल्लेख किया था)। मैं विवरण . पर केवल अनुक्रमणिका बनाऊंगा टेबल, ज्वाइन कॉलम पर, और इसमें कोई कॉलम शामिल नहीं है।
CREATE INDEX Header_index on Headers(SalesOrderID)
;
एक बार जब वह इंडेक्स बन जाता है तो हैश जॉइन चला जाता है। इंडेक्स डेटा को हेडर . में सॉर्ट करता है तालिका और SQL सर्वर को अनुक्रमणिका के क्रम अनुक्रम का उपयोग करके आंतरिक तालिका में मिलान पंक्तियों को खोजने की अनुमति देता है। अब, योजना का सबसे महंगा हिस्सा बाहरी टेबल पर स्कैन है (विवरण ) जिसे SalesOrderID . पर एक इंडेक्स बनाकर कम किया जा सकता है उस तालिका में कॉलम। मैं इसे पाठक के लिए एक अभ्यास के रूप में छोड़ दूँगा।
हालांकि, हैश जॉइन वाली योजना हमेशा एक बुरी चीज नहीं होती है। वैकल्पिक ऑपरेटर (विशेष मामलों को छोड़कर) एक नेस्टेड लूप्स जॉइन है, और यह आमतौर पर तब होता है जब अच्छे इंडेक्स मौजूद होते हैं। हालांकि, एक नेस्टेड लूप ऑपरेशन के लिए आंतरिक तालिका की एकाधिक खोजों की आवश्यकता होती है। निम्नलिखित स्यूडोकोड नेस्टेड लूप्स को एल्गोरिथम में शामिल होने को दर्शाता है:
for each row R1 in the outer table
for each row R2 in the inner table
if R1 joins with R2
return (R1, R2)
जैसा कि नाम से संकेत मिलता है, नेस्टेड लूप जॉइन नेस्टेड लूप के रूप में किया जाता है। बाहरी तालिका में प्रत्येक क्वालीफाइंग पंक्ति के लिए आंतरिक तालिका की खोज आमतौर पर कई बार की जाएगी। यहां तक कि अगर योग्य पंक्तियों में से केवल कुछ प्रतिशत हैं, यदि तालिका बहुत बड़ी है (शायद सैकड़ों लाखों, या अरबों, या पंक्तियों में) तो पढ़ने के लिए बहुत सारी पंक्तियां होंगी। I/O बाध्य प्रणाली में, ये लाखों या अरबों रीड एक वास्तविक बाधा हो सकते हैं।
दूसरी ओर, एक हैश जॉइन, किसी भी तालिका के एकाधिक रीड नहीं करता है। यह हैश बकेट बनाने के लिए बाहरी टेबल को एक बार पढ़ता है, और फिर यह एक बार इनर टेबल को पढ़ता है, हैश बकेट की जांच करता है कि क्या कोई मिलान पंक्ति है। हमारे पास प्रत्येक तालिका के माध्यम से एक एकल पास की ऊपरी सीमा है। हां, हैश फ़ंक्शन की गणना करने और बकेट की सामग्री को प्रबंधित करने के लिए CPU संसाधनों की आवश्यकता होती है। हैश की गई जानकारी को संग्रहीत करने के लिए आवश्यक स्मृति संसाधन हैं। लेकिन, यदि आपके पास I/O बाध्य प्रणाली है, तो आपके पास अतिरिक्त मेमोरी और CPU संसाधन हो सकते हैं। इन स्थितियों में जहां आपके I/O संसाधन सीमित हैं और आप बहुत बड़ी तालिकाओं में शामिल हो रहे हैं, HASH JOIN अनुकूलक के लिए एक उचित विकल्प हो सकता है।
यहाँ हैश जॉइन एल्गोरिथम के लिए स्यूडोकोड है:
for each row R1 in the build table
begin
calculate hash value on R1 join key(s)
insert R1 into the appropriate hash bucket
end
for each row R2 in the probe table
begin
calculate hash value on R2 join key(s)
for each row R1 in the corresponding hash bucket
if R1 joins with R2
output (R1, R2)
end
जैसा कि पहले उल्लेख किया गया है, हैशिंग का उपयोग एकत्रीकरण (साथ ही यूनियन) संचालन के लिए भी किया जा सकता है। दोबारा, यदि कोई उपयोगी अनुक्रमणिका है जिसमें पहले से ही डेटा सॉर्ट किया गया है, तो डेटा को समूहबद्ध करना बहुत कुशलता से किया जा सकता है। हालांकि, ऐसी कई स्थितियां भी हैं जहां हैशिंग बिल्कुल भी खराब ऑपरेटर नहीं है। निम्नलिखित की तरह एक प्रश्न पर विचार करें, जो डेटा को विवरण . में समूहित करता है ProductID . द्वारा तालिका (ऊपर बनाई गई) कॉलम। तालिका में 121,317 पंक्तियाँ हैं और केवल 266 भिन्न हैं ProductID मान।
SELECT ProductID, count(*)
FROM Details
GROUP BY ProductID;
GO
हैशिंग ऑपरेशंस का उपयोग करना
हैशिंग का उपयोग करने के लिए, SQL सर्वर को केवल 266 बकेट बनाने और बनाए रखने होते हैं, जो कि बहुत कुछ नहीं है। वास्तव में, क्वेस्ट स्पॉटलाइट ट्यूनिंग पैक यह इंगित नहीं करता है कि इस क्वेरी के साथ कोई समस्या है।
हां, इसके लिए एक टेबल स्कैन करना होता है, लेकिन ऐसा इसलिए होता है क्योंकि हमें टेबल की हर पंक्ति की जांच करनी होती है, और हम जानते हैं कि स्कैन हमेशा एक बुरी चीज नहीं होती है। एक इंडेक्स केवल डेटा को पूर्व निर्धारित करने में मदद करेगा, लेकिन इतनी कम संख्या में समूहों के लिए हैश एग्रीगेशन का उपयोग करने से आमतौर पर कोई उपयोगी इंडेक्स उपलब्ध न होने पर भी उचित प्रदर्शन मिलेगा।
टेबल स्कैन की तरह, हैशिंग संचालन को अक्सर एक योजना में 'खराब' ऑपरेटर के रूप में देखा जाता है। ऐसे मामले हैं जहां आप हैश संचालन को हटाने के लिए उपयोगी अनुक्रमणिका जोड़कर प्रदर्शन में काफी सुधार कर सकते हैं, लेकिन यह हमेशा सच नहीं होता है। और यदि आप उन तालिकाओं पर अनुक्रमणिका की संख्या को सीमित करने का प्रयास कर रहे हैं जो अत्यधिक अद्यतन हैं, तो आपको पता होना चाहिए कि हैश संचालन हमेशा कुछ ऐसा नहीं होता है जिसे 'निश्चित' करना पड़ता है, इसलिए हैश का उपयोग करने के लिए क्वेरी को छोड़ना एक उचित बात हो सकती है करने के लिए। इसके अलावा, I/O बाउंड सिस्टम पर चलने वाली बड़ी तालिकाओं पर कुछ प्रश्नों के लिए, हैशिंग वास्तव में वैकल्पिक एल्गोरिदम की तुलना में बेहतर प्रदर्शन दे सकता है क्योंकि सीमित संख्या में पढ़ने की आवश्यकता होती है। निश्चित रूप से जानने का एकमात्र तरीका, यह आपके सिस्टम पर आपके प्रश्नों और आपके डेटा के साथ विभिन्न संभावनाओं का परीक्षण करना है।
इस श्रृंखला में निम्नलिखित पोस्ट में, मैं आपको अन्य समस्याग्रस्त ऑपरेटरों के बारे में बताऊंगा जो आपकी क्वेरी योजनाओं में दिखाई दे सकते हैं, इसलिए जल्द ही वापस जांचें!