Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

नए SQL सर्वर कार्डिनैलिटी अनुमानक पर पहली नज़र

बेंजामिन नेवारेज़ लॉस एंजिल्स, कैलिफ़ोर्निया में स्थित एक स्वतंत्र सलाहकार हैं जो SQL सर्वर क्वेरी ट्यूनिंग और अनुकूलन में माहिर हैं। वह "एसक्यूएल सर्वर 2014 क्वेरी ट्यूनिंग और ऑप्टिमाइज़ेशन" और "इनसाइड द एसक्यूएल सर्वर क्वेरी ऑप्टिमाइज़र" के लेखक हैं और "एसक्यूएल सर्वर 2012 इंटर्नल्स" के सह-लेखक हैं। रिलेशनल डेटाबेस में 20 से अधिक वर्षों के अनुभव के साथ, बेंजामिन कई SQL सर्वर सम्मेलनों में एक वक्ता भी रहे हैं, जिसमें PASS समिट, SQL सर्वर कनेक्शन और SQLBits शामिल हैं। बेंजामिन का ब्लॉग http://www.benjaminnevarez.com पर पाया जा सकता है और उस तक बेंजामिननेवारेज़ डॉट कॉम के एडमिन और @BenjaminNevarez पर ट्विटर पर ई-मेल द्वारा भी पहुंचा जा सकता है।

जबकि SQL सर्वर 2014 के बारे में अधिकांश जानकारी, ब्लॉग और दस्तावेज़ीकरण ने हेकाटन और अन्य नई सुविधाओं पर ध्यान केंद्रित किया है, नए कार्डिनैलिटी अनुमानक के बारे में बहुत अधिक विवरण प्रदान नहीं किया गया है। वर्तमान में BOL केवल इसके बारे में परोक्ष रूप से व्हाट्स न्यू (डेटाबेस इंजन) अनुभाग पर बात करता है, यह कहते हुए कि SQL Server 2014 "उस घटक में पर्याप्त सुधार शामिल है जो क्वेरी योजना बनाता और अनुकूलित करता है," और ALTER DATABASE कथन दिखाता है कि इसके व्यवहार को कैसे सक्षम या अक्षम किया जाए। सौभाग्य से हम कैंपबेल फ्रेजर एट अल द्वारा SQL सर्वर में टेस्टिंग कार्डिनैलिटी एस्टीमेशन मॉडल्स के शोध पत्र को पढ़कर कुछ अतिरिक्त जानकारी प्राप्त कर सकते हैं। हालांकि पेपर का फोकस नए अनुमान मॉडल की गुणवत्ता आश्वासन प्रक्रिया है, यह नए कार्डिनैलिटी अनुमानक के लिए एक बुनियादी परिचय और इसके रीडिज़ाइन की प्रेरणा भी प्रदान करता है।

तो, कार्डिनैलिटी अनुमानक क्या है? एक कार्डिनैलिटी अनुमानक क्वेरी प्रोसेसर का घटक है जिसका काम एक क्वेरी में रिलेशनल ऑपरेशंस द्वारा लौटाई गई पंक्तियों की संख्या का अनुमान लगाना है। यह जानकारी, कुछ अन्य डेटा के साथ, एक कुशल निष्पादन योजना का चयन करने के लिए क्वेरी ऑप्टिमाइज़र द्वारा उपयोग की जाती है। कार्डिनैलिटी का अनुमान स्वाभाविक रूप से सटीक नहीं है, क्योंकि यह एक गणितीय मॉडल है जो सांख्यिकीय जानकारी पर निर्भर करता है। यह कई मान्यताओं पर भी आधारित है, हालांकि दस्तावेज नहीं हैं, लेकिन वर्षों से ज्ञात हैं - उनमें से कुछ में एकरूपता, स्वतंत्रता, रोकथाम और समावेशन धारणाएं शामिल हैं। इन मान्यताओं का संक्षिप्त विवरण इस प्रकार है।

  1. एकरूपता . इसका उपयोग तब किया जाता है जब किसी विशेषता के लिए वितरण अज्ञात होता है, उदाहरण के लिए, हिस्टोग्राम चरण में श्रेणी पंक्तियों के अंदर या जब कोई हिस्टोग्राम उपलब्ध नहीं होता है।
  2. स्वतंत्रता . इसका उपयोग तब किया जाता है जब किसी संबंध में विशेषताएँ स्वतंत्र होती हैं, जब तक कि उनके बीच कोई संबंध ज्ञात न हो।
  3. रोकथाम . जब दो विशेषताएँ समान हो सकती हैं, तो उनका उपयोग किया जाता है, उन्हें समान माना जाता है।
  4. शामिल करना . किसी विशेषता की तुलना स्थिरांक से करते समय उपयोग किया जाता है, यह माना जाता है कि हमेशा एक मिलान होता है।

यह दिलचस्प है कि मैंने हाल ही में PASS समिट में अपने अंतिम भाषण में इन मान्यताओं की कुछ सीमाओं के बारे में बात की, जिसे क्वेरी ऑप्टिमाइज़र की सीमाओं को हराना कहा जाता है। फिर भी मुझे यह पढ़कर आश्चर्य हुआ कि लेखक स्वीकार करते हैं कि व्यवहार में उनके अनुभव के अनुसार, ये धारणाएँ "अक्सर गलत" होती हैं।

वर्तमान कार्डिनैलिटी अनुमानक SQL सर्वर 7.0 के लिए संपूर्ण क्वेरी प्रोसेसर के साथ लिखा गया था, जिसे 1998 के दिसंबर में वापस जारी किया गया था। जाहिर है कि इस घटक को कई वर्षों के दौरान कई बदलावों का सामना करना पड़ा है और SQL सर्वर के कई रिलीज, जिसमें फिक्स, समायोजन और एक्सटेंशन शामिल हैं। नई टी-एसक्यूएल सुविधाओं के लिए कार्डिनैलिटी अनुमान को समायोजित करें। तो आप सोच रहे होंगे कि लगभग 15 वर्षों से सफलतापूर्वक उपयोग किए जा रहे घटक को क्यों बदला जाए?

नया कार्डिनैलिटी अनुमानक क्यों

पेपर रीडिज़ाइन के कुछ कारणों की व्याख्या करता है जिनमें शामिल हैं:

  1. कार्डिनैलिटी अनुमानक को नए कार्यभार पैटर्न में समायोजित करने के लिए।
  2. वर्षों में कार्डिनैलिटी अनुमानक में किए गए परिवर्तनों ने घटक को "डीबग करना, भविष्यवाणी करना और समझना" मुश्किल बना दिया है।
  3. वर्तमान मॉडल में सुधार करने की कोशिश करना वर्तमान आर्किटेक्चर का उपयोग करना मुश्किल था, इसलिए एक नया डिज़ाइन बनाया गया था, जो कार्यों के पृथक्करण पर केंद्रित था (ए) किसी विशेष अनुमान की गणना कैसे करें, और (बी) वास्तव में गणना करना ।

मुझे यकीन नहीं है कि माइक्रोसॉफ्ट द्वारा नए कार्डिनैलिटी अनुमानक के बारे में अधिक विवरण प्रकाशित किया जा रहा है या नहीं। आखिरकार, 15 वर्षों में पुराने कार्डिनैलिटी अनुमानक के बारे में इतने विवरण कभी प्रकाशित नहीं हुए; उदाहरण के लिए, कुछ विशिष्ट कार्डिनैलिटी अनुमान की गणना कैसे की जाती है। दूसरी ओर, नई विस्तारित घटनाएं हैं जिनका उपयोग हम कार्डिनैलिटी अनुमान के साथ समस्याओं का निवारण करने के लिए कर सकते हैं, या यह पता लगाने के लिए कि यह कैसे काम करता है। इन इवेंट में query_optimizer_estimate_cardinality . शामिल हैं , inaccurate_cardinality_estimate , query_optimizer_force_both_cardinality_estimation_behaviors और query_rpc_set_cardinality

योजना प्रतिगमन

क्वेरी ऑप्टिमाइज़र के अंदर इतने बड़े बदलाव के साथ एक बड़ी चिंता जो दिमाग में आती है, वह है प्लान रिग्रेशन। क्वेरी ऑप्टिमाइज़र सुधारों के लिए योजना प्रतिगमन के डर को सबसे बड़ी बाधा माना गया है। रिग्रेशन समस्याएँ हैं जो क्वेरी ऑप्टिमाइज़र पर एक फ़िक्स लागू होने के बाद शुरू की जाती हैं और कभी-कभी क्लासिक के रूप में संदर्भित होती हैं "दो गलतियाँ एक सही बनाती हैं।" यह तब हो सकता है जब दो खराब अनुमान, उदाहरण के लिए एक मूल्य को कम करके आंका जाता है और दूसरा इसे कम करके आंका जाता है, एक दूसरे को रद्द कर देता है, सौभाग्य से एक अच्छा अनुमान दे रहा है। इनमें से केवल एक मान को ठीक करने से अब एक खराब अनुमान हो सकता है जो योजना चयन की पसंद को नकारात्मक रूप से प्रभावित कर सकता है, जिससे एक प्रतिगमन हो सकता है।

नए कार्डिनैलिटी अनुमानक से संबंधित प्रतिगमन से बचने में मदद करने के लिए, SQL सर्वर इसे सक्षम या अक्षम करने का एक तरीका प्रदान करता है, क्योंकि यह डेटाबेस संगतता स्तर पर निर्भर करता है। इसे ALTER DATABASE . का उपयोग करके बदला जा सकता है बयान, जैसा कि पहले बताया गया है। संगतता स्तर 120 पर डेटाबेस सेट करना नए कार्डिनैलिटी अनुमानक का उपयोग करेगा, जबकि 120 से कम संगतता स्तर पुराने कार्डिनैलिटी अनुमानक का उपयोग करेगा। इसके अलावा, एक बार जब आप एक विशिष्ट कार्डिनैलिटी अनुमानक का उपयोग कर रहे होते हैं, तो दो ट्रेस फ़्लैग होते हैं जिनका उपयोग आप दूसरे में बदलने के लिए कर सकते हैं। हालांकि इस समय मुझे ट्रेस फ़्लैग कहीं भी प्रलेखित नहीं दिखाई दे रहे हैं, उनका उल्लेख query_optimizer_force_both_cardinality_estimation_behaviors के विवरण के भाग के रूप में किया गया है विस्तारित घटना। नए कार्डिनैलिटी अनुमानक को सक्षम करने के लिए ट्रेस ध्वज 2312 का उपयोग किया जा सकता है, जबकि ट्रेस ध्वज 9481 को इसे अक्षम करने के लिए उपयोग किया जा सकता है। आप QUERYTRACEON . का उपयोग करके किसी विशिष्ट क्वेरी के लिए ट्रेस फ़्लैग का उपयोग भी कर सकते हैं संकेत (हालांकि यह अभी तक प्रलेखित नहीं है कि क्या यह समर्थित होगा)।

उदाहरण

अंत में, पेपर में कुछ परीक्षण किए गए परिदृश्यों का भी उल्लेख किया गया है जैसे कि अधिक जनसंख्या वाली प्राथमिक कुंजी, सरल जुड़ाव, या आरोही कुंजी समस्या। यह यह भी दर्शाता है कि लेखकों ने कई परिदृश्यों (या मॉडल विविधताओं) के साथ कैसे प्रयोग किया और कुछ मामलों में कार्डिनैलिटी अनुमानक द्वारा बनाई गई कुछ धारणाओं को "आराम" किया, उदाहरण के लिए, स्वतंत्रता धारणा के मामले में, पूर्ण स्वतंत्रता से पूर्ण सहसंबंध तक जाना और बीच में कुछ अच्छा परिणाम मिलने तक।

हालांकि कागज पर कोई विवरण प्रदान नहीं किया गया है, मैं यह समझने की कोशिश करने के लिए इनमें से कुछ परिदृश्यों का परीक्षण शुरू करने का निर्णय लेता हूं कि नया कार्डिनैलिटी अनुमानक कैसे काम करता है। अभी के लिए मैं आपको स्वतंत्रता धारणा और आरोही कुंजियों का उपयोग करके उदाहरण दिखाऊंगा। मैंने एकरूपता की धारणा का भी परीक्षण किया लेकिन अभी तक अनुमान पर कोई अंतर नहीं पाया।

आइए स्वतंत्रता धारणा उदाहरण से शुरू करें। आइए पहले वर्तमान व्यवहार को देखें। उसके लिए, एडवेंचरवर्क्स2012 डेटाबेस पर निम्न कथन चलाकर सुनिश्चित करें कि आप पुराने कार्डिनैलिटी अनुमानक का उपयोग कर रहे हैं:

ALTER DATABASE AdventureWorks2012 SET COMPATIBILITY_LEVEL = 110;

फिर दौड़ें:

SELECT * FROM Person.Address WHERE City = 'Burbank';

जैसा कि आगे दिखाया गया है, हमें अनुमानित 196 रिकॉर्ड मिलते हैं:

इसी प्रकार निम्नलिखित कथनों का अनुमानतः 194 प्राप्त होगा:

SELECT * FROM Person.Address WHERE PostalCode = '91502';

यदि हम दोनों विधेय का उपयोग करते हैं तो हमारे पास निम्न क्वेरी है, जिसमें अनुमानित पंक्तियों की संख्या 1.93862 होगी (SQL संतरी योजना एक्सप्लोरर का उपयोग करते हुए 2 पंक्तियों तक गोल):

SELECT * FROM Person.Address WHERE City = 'Burbank' AND PostalCode = '91502';

इस मान की गणना दोनों विधेय की कुल स्वतंत्रता को मानकर की जाती है, जो सूत्र (196 * 194) / 19614.0 (जहाँ 19614 तालिका में पंक्तियों की कुल संख्या है) का उपयोग करता है। कुल सहसंबंध का उपयोग करने से हमें 194 का अनुमान लगाना चाहिए, क्योंकि डाक कोड 91502 वाले सभी रिकॉर्ड बरबैंक के हैं। नया कार्डिनैलिटी अनुमानक एक ऐसे मूल्य का अनुमान लगाता है जो कुल स्वतंत्रता या कुल सहसंबंध को नहीं मानता है। निम्नलिखित कथन का उपयोग करके नए कार्डिनैलिटी अनुमानक में बदलें:

ALTER DATABASE AdventureWorks2012 SET COMPATIBILITY_LEVEL = 120;
GO
 
SELECT * FROM Person.Address WHERE City = 'Burbank' AND PostalCode = '91502';

उसी कथन को फिर से चलाने से 19.3931 पंक्तियों का अनुमान मिलेगा, जिसे आप देख सकते हैं कि कुल स्वतंत्रता और कुल सहसंबंध (प्लान एक्सप्लोरर में 19 पंक्तियों तक) के बीच का मान है। उपयोग किया गया सूत्र सबसे चयनात्मक फ़िल्टर की चयनात्मकता है * SQRT (अगले सबसे चयनात्मक फ़िल्टर की चयनात्मकता) या (194/19614.0) * SQRT(196/19614.0) * 19614 जो 19.393 देता है:

यदि आपने डेटाबेस स्तर पर नए कार्डिनैलिटी अनुमानक को सक्षम किया है तो योजना प्रतिगमन से बचने के लिए इसे किसी विशिष्ट क्वेरी के लिए अक्षम करना चाहते हैं, तो आप पहले बताए अनुसार ट्रेस फ्लैग 9481 का उपयोग कर सकते हैं:

ALTER DATABASE AdventureWorks2012 SET COMPATIBILITY_LEVEL = 120;
GO
 
SELECT * FROM Person.Address WHERE City = 'Burbank' AND PostalCode = '91502'
  OPTION (QUERYTRACEON 9481);

नोट:QUERYTRACEON क्वेरी संकेत का उपयोग क्वेरी स्तर पर ट्रेस फ़्लैग लागू करने के लिए किया जाता है और वर्तमान में यह केवल सीमित संख्या में परिदृश्यों में समर्थित है। QUERYTRACEON क्वेरी संकेत के बारे में अधिक जानकारी के लिए आप http://support.microsoft.com/kb/2801413 पर देख सकते हैं।

अब हम आरोही प्रमुख समस्या को देखते हैं, एक विषय जिसे मैंने इस पोस्ट में और अधिक विस्तार से समझाया है। इस समस्या को ठीक करने के लिए Microsoft की पारंपरिक अनुशंसा डेटा लोड करने के बाद आंकड़ों को मैन्युअल रूप से अपडेट करना है, जैसा कि यहां बताया गया है - जो निम्न तरीके से समस्या का वर्णन करता है:

<ब्लॉककोट>

आरोही या अवरोही कुंजी कॉलम के आंकड़े, जैसे पहचान या रीयल-टाइम टाइमस्टैम्प कॉलम, क्वेरी ऑप्टिमाइज़र के प्रदर्शन की तुलना में अधिक लगातार आंकड़े अपडेट की आवश्यकता हो सकती है। इन्सर्ट ऑपरेशंस नए मानों को आरोही या अवरोही कॉलम में जोड़ते हैं। जोड़ी गई पंक्तियों की संख्या आंकड़े अपडेट को ट्रिगर करने के लिए बहुत कम हो सकती है। यदि आंकड़े अप-टू-डेट नहीं हैं और हाल ही में जोड़ी गई पंक्तियों में से क्वेरी का चयन किया जाता है, तो वर्तमान आंकड़ों में इन नए मानों के लिए कार्डिनैलिटी अनुमान नहीं होंगे। इसके परिणामस्वरूप गलत कार्डिनैलिटी अनुमान और धीमी क्वेरी प्रदर्शन हो सकता है। उदाहरण के लिए, सबसे हालिया बिक्री आदेश तिथियों में से चयन करने वाली एक क्वेरी में गलत कार्डिनैलिटी अनुमान होंगे यदि आंकड़ों को नवीनतम बिक्री आदेश तिथियों के कार्डिनैलिटी अनुमानों को शामिल करने के लिए अद्यतन नहीं किया जाता है।

मेरे लेख में अनुशंसा ट्रेस फ़्लैग्स 2389 और 2390 का उपयोग करने की थी, जिसे पहली बार इयान जोस ने अपने लेख आरोही कुंजी और ऑटो त्वरित सुधार सांख्यिकी में प्रकाशित किया था। आप इस समस्या से बचने के लिए इन ट्रेस फ़्लैग्स का उपयोग करने के तरीके के बारे में स्पष्टीकरण और उदाहरण के लिए मेरा लेख पढ़ सकते हैं। ये ट्रेस फ़्लैग अभी भी SQL Server 2014 CTP2 पर कार्य करते हैं। लेकिन इससे भी बेहतर, यदि आप नए कार्डिनैलिटी अनुमानक का उपयोग कर रहे हैं तो उनकी अब कोई आवश्यकता नहीं है।

मेरी पोस्ट में उसी उदाहरण का उपयोग करना:

CREATE TABLE dbo.SalesOrderHeader (
    SalesOrderID int NOT NULL,
    RevisionNumber tinyint NOT NULL,
    OrderDate datetime NOT NULL,
    DueDate datetime NOT NULL,
    ShipDate datetime NULL,
    Status tinyint NOT NULL,
    OnlineOrderFlag dbo.Flag NOT NULL,
    SalesOrderNumber nvarchar(25) NOT NULL,
    PurchaseOrderNumber dbo.OrderNumber NULL,
    AccountNumber dbo.AccountNumber NULL,
    CustomerID int NOT NULL,
    SalesPersonID int NULL,
    TerritoryID int NULL,
    BillToAddressID int NOT NULL,
    ShipToAddressID int NOT NULL,
    ShipMethodID int NOT NULL,
    CreditCardID int NULL,
    CreditCardApprovalCode varchar(15) NULL,
    CurrencyRateID int NULL,
    SubTotal money NOT NULL,
    TaxAmt money NOT NULL,
    Freight money NOT NULL,
    TotalDue money NOT NULL,
    Comment nvarchar(128) NULL,
    rowguid uniqueidentifier NOT NULL,
    ModifiedDate datetime NOT NULL
);

कुछ डेटा डालें:

INSERT INTO dbo.SalesOrderHeader SELECT * FROM Sales.SalesOrderHeader 
WHERE OrderDate &lt; '2008-07-20 00:00:00.000';
 
CREATE INDEX IX_OrderDate ON SalesOrderHeader(OrderDate);

चूंकि हमने एक इंडेक्स बनाया है, इसलिए हमारे पास सिर्फ नए आंकड़े हैं। निम्नलिखित क्वेरी को चलाने से 35 पंक्तियों का एक अच्छा अनुमान बन जाएगा:

SELECT * FROM dbo.SalesOrderHeader WHERE OrderDate = '2008-07-19 00:00:00.000';

अगर हम नया डेटा डालते हैं:

INSERT INTO dbo.SalesOrderHeader SELECT * FROM Sales.SalesOrderHeader 
WHERE OrderDate = '2008-07-20 00:00:00.000';

आप पुराने कार्डिनैलिटी अनुमानक के साथ अनुमान देख सकते हैं जैसा कि आगे दिखाया गया है:

ALTER DATABASE AdventureWorks2012 SET COMPATIBILITY_LEVEL = 110;
GO
 
SELECT * FROM dbo.SalesOrderHeader WHERE OrderDate = '2008-07-20 00:00:00.000';

चूंकि सम्मिलित किए गए रिकॉर्ड की छोटी संख्या सांख्यिकी ऑब्जेक्ट के स्वचालित अपडेट को ट्रिगर करने के लिए पर्याप्त नहीं थी, वर्तमान हिस्टोग्राम को जोड़े गए नए रिकॉर्ड के बारे में पता नहीं है और क्वेरी ऑप्टिमाइज़र अनुमानित 1 पंक्ति का उपयोग करता है। वैकल्पिक रूप से आप बेहतर अनुमान प्राप्त करने में सहायता के लिए ट्रेस फ़्लैग 2389 और 2390 का उपयोग कर सकते हैं। लेकिन अगर आप नए कार्डिनैलिटी अनुमानक के साथ एक ही प्रश्न का प्रयास करते हैं, तो आपको निम्न अनुमान मिलता है:

ALTER DATABASE AdventureWorks2012 SET COMPATIBILITY_LEVEL = 120;
GO
 
SELECT * FROM dbo.SalesOrderHeader WHERE OrderDate = '2008-07-20 00:00:00.000';

इस मामले में हमें पुराने कार्डिनैलिटी अनुमानक की तुलना में बेहतर अनुमान मिलता है (या हमें ट्रेस फ्लैग 2389 या 2390 का उपयोग करने के समान अनुमान मिलता है)। 27.9631 के अनुमानित मूल्य (प्लान एक्सप्लोरर द्वारा फिर से 28 के लिए गोल) की गणना तालिका की पंक्तियों की संख्या से गुणा की गई सांख्यिकी वस्तु की घनत्व जानकारी का उपयोग करके की जाती है; यानी 0.0008992806 * 31095। घनत्व मान का उपयोग करके प्राप्त किया जा सकता है:

DBCC SHOW_STATISTICS('dbo.SalesOrderHeader', 'IX_OrderDate');

अंत में, ध्यान रखें कि इस आलेख में उल्लिखित कुछ भी प्रलेखित नहीं है, और यह वह व्यवहार है जिसे मैंने अब तक SQL Server 2014 CTP2 में देखा है। इनमें से कोई भी बाद के सीटीपी या उत्पाद के आरटीएम संस्करण में बदल सकता है।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. जब IDENTITY_INSERT को OFF पर सेट किया जाता है, तो तालिका 'तालिका' में पहचान कॉलम के लिए स्पष्ट मान सम्मिलित नहीं किया जा सकता है

  2. SQL सर्वर:पूल किए गए कनेक्शन में अलगाव स्तर लीक

  3. नल के साथ SQL सर्वर स्ट्रिंग संयोजन

  4. SQL सर्वर में एस्केप कैरेक्टर

  5. एन्क्रिप्टेड कनेक्शन SQL सर्वर के लिए प्रमाणपत्र परिनियोजित करना