SQL सर्वर को लगभग 30 साल से अधिक हो गए हैं, और मैं SQL सर्वर के साथ लगभग लंबे समय से काम कर रहा हूं। मैंने इस अविश्वसनीय उत्पाद के वर्षों (और दशकों!) और संस्करणों में बहुत सारे बदलाव देखे हैं। इन पोस्टों में मैं आपके साथ साझा करूँगा कि मैं SQL सर्वर की कुछ विशेषताओं या पहलुओं को कैसे देखता हूँ, कभी-कभी कुछ ऐतिहासिक परिप्रेक्ष्य के साथ।
समस्याग्रस्त ऑपरेटरों पर कलेन के हाल के ब्लॉग यहां देखें।
SQL सर्वर डायग्नोस्टिक्स के लिए योजनाएं बनाना महंगा हो सकता है, क्योंकि क्वेरी ऑप्टिमाइज़र को सबमिट की गई किसी भी कानूनी क्वेरी के लिए एक अच्छी योजना खोजने में सक्षम होना चाहिए। ऑप्टिमाइज़र मल्टीपल जॉइन ऑर्डर, मल्टीपल इंडेक्स का मूल्यांकन करता है। और आपकी क्वेरी और शामिल तालिकाओं के आधार पर विभिन्न प्रकार के जॉइन और ग्रुपिंग एल्गोरिदम। यदि वही क्वेरी फिर से चलाई जाती है, तो SQL सर्वर मौजूदा योजना का पुन:उपयोग करके बहुत सारे संसाधनों को बचा सकता है। लेकिन किसी मौजूदा योजना का पुन:उपयोग करना हमेशा संभव नहीं होता है, और ऐसा करना हमेशा अच्छी बात नहीं होती है। अगले दो लेखों में, हम देखेंगे कि कब किसी योजना का पुन:उपयोग किया जाता है और कब इसे पुन:संकलित किया जाता है।
सबसे पहले, हम योजनाओं के विभिन्न स्वादों और मेटाडेटा दृश्य को देखेंगे जिसका उपयोग मैं अपने प्लान कैश में देखने के लिए सबसे अधिक बार करता हूं। मैंने अपना खुद का एक दृश्य लिखा है जो वह जानकारी प्रदान करता है जो मुझे सबसे अधिक उपयोगी लगता है। SQL सर्वर छह अलग-अलग प्रकार की क्वेरी योजनाओं को कैश करता है, लेकिन सामान्य रूप से केवल दो का उपयोग प्लान कैश ट्यूनिंग के लिए किया जाता है। ये संकलित योजना और संकलित योजना ठूंठ हैं। मेरा विचार इन दो प्रकार के कैश ऑब्जेक्ट्स को छोड़कर सभी को फ़िल्टर करता है। संकलित योजनाएँ तीन किस्मों में आती हैं:AD HOC, PREPARED, और PROC। मैं तीनों प्रकार की टिप्पणी करूंगा।
यहां तक कि अगर हम केवल संकलित योजनाओं को देख रहे हैं, तब भी कैश में बहुत सी योजनाएं हैं जिन्हें आमतौर पर अनदेखा करने की आवश्यकता होती है, क्योंकि वे SQL सर्वर द्वारा ही उत्पन्न होती हैं। इनमें फाइलस्ट्रीम या फुल-टेक्स्ट सर्च इंडेक्स या इन-मेमोरी ओएलटीपी के साथ काम करने वाली आंतरिक क्वेरी की तलाश करने वाली योजनाएं शामिल हैं। इसलिए, मेरा विचार उन अधिकांश योजनाओं को आज़माने के लिए फ़िल्टर जोड़ता है जिनमें मेरी रुचि नहीं है। आप इस दृश्य को बनाने के लिए एक स्क्रिप्ट डाउनलोड कर सकते हैं, जिसे sp_cacheobjects कहा जाता है। , यहां से।
मेरे विचार द्वारा उपयोग किए जाने वाले सभी फ़िल्टर के साथ भी, कैश में SQL सर्वर के कुछ आंतरिक प्रश्न अभी भी हैं; मैं आमतौर पर इस क्षेत्र में परीक्षण करते समय योजना कैश को बार-बार साफ़ करता हूँ। कैश से सभी योजनाओं को साफ़ करने का सबसे आसान तरीका है:DBCC FREEPROCCACHE।
तदर्थ संकलित योजनाएं
एडहॉक योजना का सबसे सरल प्रकार है। इसका उपयोग उन बुनियादी प्रश्नों के लिए किया जाता है जो किसी अन्य श्रेणी में फिट नहीं होते हैं। यदि आपने मेरी स्क्रिप्ट डाउनलोड की है और मेरा sp_cacheobjects दृश्य बनाया है, तो आप निम्न को चला सकते हैं। एडवेंचरवर्क्स डेटाबेस के किसी भी संस्करण को काम करना चाहिए। यह स्क्रिप्ट एक टेबल की कॉपी बनाती है और उस पर कुछ यूनिक इंडेक्स बनाती है। यह किसी भी दशमलव अंक को हटाने के लिए सबटोटल राशि की मालिश भी करता है।
USE AdventureWorks2016;
GODROP TABLE IF EXISTS newsales;
GO-- Make a copy of the Sales.SalesOrderHeader table
SELECT * INTO dbo.newsales
FROM Sales.SalesOrderHeader;
GOUPDATE dbo.newsales
SET SubTotal = cast(cast(SubTotal as int) as money);
GOCREATE UNIQUE index newsales_ident
ON newsales(SalesOrderID);
GOCREATE INDEX IX_Sales_SubTotal ON newsales(SubTotal);
GO-- Adhoc query plan reuse
DBCC FREEPROCCACHE;
GO-- adhoc query
SELECT * FROM dbo.newsales
WHERE SubTotal = 4;
GOSELECT * FROM sp_cacheobjects;
GO
मेरे आउटपुट में, आप दो एडहॉक प्लान देखते हैं। एक newsales . के SELECT स्टेटमेंट के लिए है तालिका, और दूसरा मेरे sp_cacheobjects . से चयन के लिए है दृश्य। चूंकि योजना कैश की गई है, यदि सटीक वही क्वेरी फिर से चलाई जाती है, तो उसी योजना का पुन:उपयोग किया जा सकता है और आप उपयोग गणना देखेंगे मूल्य वृद्धि। हालांकि, वहाँ एक पकड़ है। एक एडहॉक योजना का पुन:उपयोग करने के लिए, SQL स्ट्रिंग बिल्कुल समान होनी चाहिए। यदि आप SQL में कोई वर्ण बदलते हैं, तो क्वेरी को उसी क्वेरी के रूप में पहचाना नहीं जाता है, और एक नई योजना उत्पन्न होती है। अगर मैं एक स्थान भी जोड़ता हूं, टिप्पणी शामिल करता हूं, या एक नया लाइन ब्रेक करता हूं, तो यह वही स्ट्रिंग नहीं है। अगर मैं मामले को बदलता हूं, तो इसका मतलब है कि अलग-अलग ASCII कोड मान हैं, इस प्रकार समान स्ट्रिंग नहीं हैं।
newsales . से मेरे पहले SELECT स्टेटमेंट के विभिन्न रूपों को चलाकर आप इसे स्वयं आज़मा सकते हैं टेबल। आप प्रत्येक के लिए कैश में एक अलग पंक्ति देखेंगे। कई विविधताओं को चलाने के बाद - जिस नंबर को मैं खोज रहा था उसे बदलना, केस बदलना, टिप्पणी जोड़ना, और एक नई लाइन, मुझे कैश में निम्नलिखित दिखाई देता है। मेरे विचार से चयन का पुन:उपयोग किया जा रहा है, लेकिन बाकी सभी चीजों में उपयोग गणना है 1.
. का मानतदर्थ क्वेरी योजना के पुन:उपयोग के लिए एक अतिरिक्त आवश्यकता यह है कि क्वेरी चलाने वाले सत्र में वही SET विकल्प प्रभावी होने चाहिए . आउटपुट में एक और कॉलम है जिसे आप क्वेरी टेक्स्ट के दाईं ओर देख सकते हैं, जिसे SETOPTS कहा जाता है। यह प्रत्येक प्रासंगिक SET विकल्प के लिए थोड़ा सा स्ट्रिंग है। यदि आप विकल्पों में से एक को बदलते हैं, उदाहरण के लिए, ANSI_NULLS OFF सेट करें, तो बिट स्ट्रिंग बदल जाएगी और मूल बिट स्ट्रिंग वाली समान योजना का पुन:उपयोग नहीं किया जा सकता है।
तैयार संकलित योजनाएँ
दूसरे प्रकार की कैश्ड संकलित योजना एक तैयार योजना है। यदि आपकी क्वेरी आवश्यकताओं के एक निश्चित सेट को पूरा करती है। यह वास्तव में स्वचालित रूप से पैरामीटरयुक्त हो सकता है। यह मेटाडेटा में PREPARED के रूप में दिखाई देता है और SQL स्ट्रिंग एक पैरामीटर मार्कर दिखाता है। यहाँ एक उदाहरण है:
PREPARED योजना पैरामीटर मार्कर को @1 के रूप में दिखाती है और इसमें वास्तविक मान शामिल नहीं है। ध्यान दें कि 5555 के वास्तविक मूल्य के साथ ADHOC क्वेरी के लिए एक पंक्ति है, लेकिन यह वास्तव में वास्तविक क्वेरी का केवल एक 'शेल' है। यह पूरी योजना को कैश नहीं करता है, लेकिन केवल क्वेरी और कुछ पहचान विवरण, क्वेरी प्रोसेसर को कैश में पैरामीटरयुक्त योजना खोजने में मदद करने के लिए। आकार पर ध्यान दें (प्रयुक्त पृष्ठ ) तैयार योजना से बहुत छोटा है।
डिफ़ॉल्ट पैरामीटरकरण मोड, जिसे SIMPLE पैरामीटराइज़ेशन कहा जाता है, इस बारे में बेहद सख्त है कि किन योजनाओं को पैरामीटराइज़ किया जा सकता है। यह वास्तव में केवल सबसे सरल प्रश्न हैं जो डिफ़ॉल्ट रूप से पैरामीटर करने योग्य हैं। ऐसी क्वेरीज़ जिनमें JOIN, GROUP BY, OR, और कई अन्य अपेक्षाकृत सामान्य क्वेरी संरचनाएँ होती हैं, किसी क्वेरी को पैरामीटराइज़ होने से रोकती हैं। इनमें से कोई भी निर्माण नहीं होने के अलावा, SIMPLE पैरामीटराइजेशन के लिए सबसे महत्वपूर्ण बात यह है कि क्वेरी सुरक्षित है। इसका मतलब यह है कि केवल एक ही संभावित योजना है चाहे किसी भी पैरामीटर के लिए कोई भी मान पारित किया गया हो। (बेशक, बिना किसी पैरामीटर वाली क्वेरी सेफ भी हो सकती है।) मेरी क्वेरी SalesOrderID कॉलम पर सटीक मिलान की तलाश में है। , जिस पर एक अद्वितीय अनुक्रमणिका है। तो मौजूदा गैर-संकुल सूचकांक का उपयोग किसी भी मिलान पंक्ति को खोजने के लिए किया जा सकता है। कोई फर्क नहीं पड़ता कि मैं किस मूल्य का उपयोग करता हूं, 55555 या कुछ और, कभी भी एक से अधिक पंक्ति नहीं होगी जिसका अर्थ है कि योजना अभी भी अच्छी होगी।
मेरे एडहॉक क्वेरी प्लान उदाहरण में, मैं सबटोटल . के लिए मेल खाने वाले मानों की तलाश कर रहा था . कुछ उपयोग मान कुछ बार होते हैं या बिल्कुल नहीं, इसलिए एक गैर-संकुल सूचकांक अच्छा होगा। लेकिन अन्य मान कई बार हो सकते हैं, इसलिए सूचकांक उपयोगी नहीं होगा। इस प्रकार, क्वेरी योजना सुरक्षित नहीं है और क्वेरी को पैरामीटरयुक्त नहीं किया जा सकता है। इसलिए हमने अपने पहले उदाहरण के लिए एक एडहॉक योजना देखी।
यदि आपके पास जॉइन या अन्य अस्वीकृत निर्माणों के साथ प्रश्न हैं, तो आप SQL सर्वर को डेटाबेस विकल्प को बदलकर पैरामीटरिंग में अधिक आक्रामक होने के लिए कह सकते हैं:
ALTER DATABASE AdventureWorks2016 SET parameterization FORCED;
GO
अपने डेटाबेस को FORCED पैरामीटराइज़ेशन पर सेट करने का अर्थ है कि SQL सर्वर जॉइन, ग्रुप बाय, OR, आदि सहित बहुत अधिक प्रश्नों को पैरामीटर करेगा, लेकिन इसका मतलब यह भी है कि SQL सर्वर एक क्वेरी को पैरामीटर कर सकता है जो सुरक्षित नहीं है। यह एक योजना के साथ आ सकता है जो केवल कुछ पंक्तियों को वापस करने पर अच्छा होता है, और फिर कई पंक्तियों को वापस करने पर योजना का पुन:उपयोग करता है। यह बहुत ही उप-इष्टतम प्रदर्शन के साथ समाप्त हो सकता है।
तैयार योजना के लिए एक अंतिम विकल्प तब होता है जब आप स्पष्ट रूप से एक योजना तैयार करते हैं। यह व्यवहार आमतौर पर SQLPrepare . के साथ एक एप्लिकेशन के माध्यम से लागू किया जाता है और SQLExecute एपीआई। आप निर्दिष्ट करते हैं कि पैरामीटर चिह्नों के साथ क्वेरी क्या है, आप डेटा प्रकार निर्दिष्ट करते हैं और आप उपयोग करने के लिए विशिष्ट मान निर्दिष्ट करते हैं। फिर उसी क्वेरी को विभिन्न विशिष्ट मानों के साथ फिर से चलाया जा सकता है और मौजूदा योजना का उपयोग किया जाएगा। यद्यपि स्पष्ट रूप से तैयार योजनाओं का उपयोग उन मामलों के लिए किया जा सकता है जहां SQL सर्वर पैरामीटर नहीं कर रहा है और आप चाहते हैं कि यह SQL सर्वर को ऐसी योजना का उपयोग करने से नहीं रोकता जो बाद के पैरामीटर के लिए अच्छा नहीं है। आपको कई अलग-अलग इनपुट मानों के साथ अपने प्रश्नों का परीक्षण करने की आवश्यकता है, और सुनिश्चित करें कि जब कोई योजना पुन:उपयोग की जाती है तो आपको अपेक्षित प्रदर्शन मिलता है।
मेटाडेटा (उदा. मेरी sp_cacheobjects देखें) केवल तीनों प्रकार की योजनाओं के लिए तैयार दिखाता है:जबरन और सरल ऑटोपैरामीटरीकरण और स्पष्ट पैरामीटरकरण।
प्रोक कंपाइल प्लान्स
अंतिम objtype संकलित योजनाओं के लिए मूल्य एक संग्रहित प्रक्रिया के लिए है, जिसे प्रोक के रूप में दिखाया गया है। जब संभव हो, सर्वर से प्रबंधन में आसानी के कारण, संग्रहीत कार्यविधियाँ पुन:प्रयोज्य कोड के लिए सबसे अच्छा विकल्प हैं, लेकिन इसका मतलब यह नहीं है कि वे हमेशा सर्वश्रेष्ठ प्रदर्शन देने की गारंटी देते हैं। जैसे कि FORCED पैरामीटराइज़ेशन विकल्प (और स्पष्ट पैरामीटराइज़ेशन) का उपयोग करते हुए, संग्रहीत कार्यविधियाँ 'पैरामीटर सूँघने' का उपयोग करती हैं। इसका मतलब है कि पारित किया गया पहला पैरामीटर मान योजना निर्धारित करता है। यदि बाद के निष्पादन उसी योजना के साथ अच्छा प्रदर्शन करते हैं, तो पैरामीटर सूँघना कोई समस्या नहीं है और वास्तव में फायदेमंद हो सकता है क्योंकि यह हमें पुन:संकलन और पुन:अनुकूलन की लागत बचाता है। हालांकि, अगर बाद में विभिन्न मूल्यों के साथ निष्पादन मूल योजना का उपयोग नहीं करना चाहिए, तो हमें समस्या है। मैं आपको पैरामीटर सूँघने का एक उदाहरण दिखाता हूँ जिससे समस्या हो रही है
मैं समाचार . के आधार पर एक संग्रहीत कार्यविधि बनाऊंगा तालिका जो हमने पहले इस्तेमाल की थी। प्रक्रिया में एक ही क्वेरी होगी, जो SalesOrderID . के आधार पर फ़िल्टर करती है कॉलम, जिस पर हमने एक गैर-संकुल सूचकांक बनाया है। क्वेरी एक असमानता पर आधारित होगी, इसलिए कुछ मानों के लिए क्वेरी केवल कुछ पंक्तियों को वापस कर सकती है, और अनुक्रमणिका का उपयोग कर सकती है, और अन्य मानों के लिए, क्वेरी बहुत सारी पंक्तियाँ लौटा सकती है। दूसरे शब्दों में, क्वेरी सुरक्षित नहीं है।
USE AdventureWorks2016;
GO
DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
@num int
AS
SELECT * FROM dbo.newsales
WHERE SalesOrderID < @num;
GO
प्रक्रिया निष्पादित होने पर कितना काम किया जा रहा है, यह देखने के लिए मैं SET STATISTICS IO ON विकल्प का उपयोग करूंगा। सबसे पहले, मैं इसे एक ऐसे पैरामीटर के साथ निष्पादित करूँगा जो केवल कुछ पंक्तियाँ लौटाता है:
SET STATISTICS IO ON
GO
EXEC get_sales_range 43700;
GO
STATISTICS IO मान रिपोर्ट करता है कि 41 पंक्तियों को वापस करने के लिए 43 तार्किक रीड्स लगे। गैर-संकुल सूचकांक के लिए यह सामान्य है। अब हम प्रक्रिया को फिर से एक बहुत बड़े मूल्य के साथ निष्पादित करते हैं।
EXEC get_sales_range 66666;
GO
SELECT * FROM sp_cacheobjects;
GO
This time, we see that SQL Server used a whole lot more reads:
वास्तव में, न्यूसेल्स पर एक टेबल स्कैन तालिका में केवल 843 रीड होते हैं, इसलिए यह टेबल स्कैन की तुलना में कहीं अधिक खराब प्रदर्शन है। sp_cacheobjects दृश्य हमें दिखाता है कि इस दूसरे निष्पादन के लिए PROC योजना का पुन:उपयोग किया गया है। यह एक उदाहरण है जब पैरामीटर सूँघना अच्छी बात नहीं है।
तो, जब पैरामीटर सूँघना एक समस्या है तो हम क्या कर सकते हैं? अगली पोस्ट में, मैं आपको बताऊंगा कि जब SQL सर्वर एक नई योजना के साथ आता है, और पुराने का पुन:उपयोग नहीं करता है। हम देखेंगे कि आप पुनर्संकलन को कैसे बाध्य (या प्रोत्साहित) कर सकते हैं, और साथ ही, हम देखेंगे कि SQL सर्वर स्वचालित रूप से आपके प्रश्नों को कब पुन:संकलित करता है।
स्पॉटलाइट क्लाउड आपके प्रदर्शन की निगरानी और SQL सर्वर निदान में क्रांति ला सकता है। नीचे दिए गए लिंक का उपयोग करके अपने नि:शुल्क परीक्षण के साथ आरंभ करें: