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

क्यों अनुकूलक बफर पूल ज्ञान का उपयोग नहीं करता

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

एक बात जो मुझसे कई बार पूछी गई है, वह यह है कि ऑप्टिमाइज़र इस बात पर विचार क्यों नहीं करता है कि क्वेरी प्लान को संकलित करते समय SQL सर्वर बफर पूल में क्या है, निश्चित रूप से यह क्वेरी को तेजी से निष्पादित कर सकता है। इस पोस्ट में, मैं समझाता हूँ कि क्यों।

बफर पूल सामग्री का पता लगाना

ऑप्टिमाइज़र बफर पूल को अनदेखा करने का पहला कारण यह है कि बफर पूल को व्यवस्थित करने के तरीके के कारण बफर पूल में क्या है, यह पता लगाना एक गैर-तुच्छ समस्या है। डेटा फ़ाइल पृष्ठ बफ़र पूल में बफ़र्स नामक छोटी डेटा संरचनाओं द्वारा नियंत्रित होते हैं, जो (गैर-विस्तृत सूची) जैसी चीज़ों को ट्रैक करते हैं:

  • पेज की आईडी (फाइल नंबर:पेज-नंबर-इन-फाइल)
  • पिछली बार जब पृष्ठ का संदर्भ दिया गया था (आलसी लेखक द्वारा कम से कम हाल ही में उपयोग किए गए एल्गोरिदम को लागू करने में मदद के लिए उपयोग किया गया था जो जरूरत पड़ने पर खाली स्थान बनाता है)
  • बफर पूल में 8KB पेज की मेमोरी लोकेशन
  • पृष्ठ गंदा है या नहीं (एक गंदे पृष्ठ में ऐसे परिवर्तन हैं जो अभी तक टिकाऊ भंडारण में वापस नहीं लिखे गए हैं)
  • पृष्ठ जिस आवंटन इकाई से संबंधित है (यहां समझाया गया है) और आवंटन इकाई आईडी का उपयोग यह पता लगाने के लिए किया जा सकता है कि पृष्ठ किस तालिका और अनुक्रमणिका का हिस्सा है

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

यदि आप रुचि रखते हैं, तो मैंने कुछ समय पहले कुछ टी-एसक्यूएल कोड के साथ एक पोस्ट लिखा था जो बफर पूल को स्कैन करता है और डीएमवी sys.dm_os_buffer_descriptors का उपयोग करके कुछ मीट्रिक देता है। ।

बफर पूल सामग्री का उपयोग करना खतरनाक क्यों होगा

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

मैं जिस परिदृश्य का उपयोग करने जा रहा हूं वह इस प्रकार है:एक टेबल बिगटेबल में दो गैर-संकुल सूचकांक हैं, इंडेक्स_ए और इंडेक्स_बी, दोनों पूरी तरह से एक विशेष क्वेरी को कवर करते हैं। क्वेरी परिणामों को पुनः प्राप्त करने के लिए क्वेरी को इंडेक्स के लीफ स्तर के पूर्ण स्कैन की आवश्यकता होती है। तालिका में 1 मिलियन पंक्तियाँ हैं। Index_A के लीफ स्तर पर 200,000 पृष्ठ हैं, और Index_B के लीफ स्तर पर 1 मिलियन पृष्ठ हैं, इसलिए Index_B के पूर्ण स्कैन के लिए पांच गुना अधिक पृष्ठों को संसाधित करने की आवश्यकता है।

मैंने 8 प्रोसेसर कोर, 32GB मेमोरी और सॉलिड-स्टेट डिस्क के साथ SQL Server 2019 चलाने वाले लैपटॉप पर यह काल्पनिक उदाहरण बनाया है। कोड इस प्रकार है:

CREATE TABLE BigTable (
  	c1 BIGINT IDENTITY,
  	c2 AS (c1 * 2),
  	c3 CHAR (1500) DEFAULT 'a',
  	c4 CHAR (5000) DEFAULT 'b'
);
GO
 
INSERT INTO BigTable DEFAULT VALUES;
GO 1000000
 
CREATE NONCLUSTERED INDEX Index_A ON BigTable (c2) INCLUDE (c3);
-- 5 records per page = 200,000 pages
GO
 
CREATE NONCLUSTERED INDEX Index_B ON BigTable (c2) INCLUDE (c4);
-- 1 record per page = 1 million pages
GO
 
CHECKPOINT;
GO

और फिर मैंने काल्पनिक प्रश्नों को समयबद्ध किया:

DBCC DROPCLEANBUFFERS;
GO
 
-- Index_A not in memory
SELECT SUM (c2) FROM BigTable WITH (INDEX (Index_A));
GO
-- CPU time = 796 ms, elapsed time = 764 ms
 
-- Index_A in memory
SELECT SUM (c2) FROM BigTable WITH (INDEX (Index_A));
GO
-- CPU time = 312 ms, elapsed time = 52 ms
 
DBCC DROPCLEANBUFFERS;
GO
 
-- Index_B not in memory
SELECT SUM (c2) FROM BigTable WITH (INDEX (Index_B));
GO
-- CPU time = 2952 ms, elapsed time = 2761 ms
 
-- Index_B in memory
SELECT SUM (c2) FROM BigTable WITH (INDEX (Index_B));
GO
-- CPU time = 1219 ms, elapsed time = 149 ms

आप देख सकते हैं कि न तो इंडेक्स मेमोरी में है, इंडेक्स_ए आसानी से उपयोग करने के लिए सबसे कुशल इंडेक्स है, जिसमें इंडेक्स_बी का उपयोग करते हुए 2,761ms के मुकाबले 764ms का बीता हुआ क्वेरी समय है, और जब दोनों इंडेक्स मेमोरी में होते हैं तो यह सच होता है। हालांकि, अगर Index_B मेमोरी में है, और Index_A नहीं है, अगर क्वेरी Index_B (149ms) का उपयोग करती है तो यह Index_A (764ms) का उपयोग करने की तुलना में तेजी से चलने वाली है।

अब ऑप्टिमाइज़र को बफर पूल में क्या है, इस पर योजना के चुनाव को आधार बनाने की अनुमति दें…

यदि इंडेक्स_ए ज्यादातर मेमोरी में नहीं है और इंडेक्स_बी ज्यादातर मेमोरी में है, तो उस इंस्टेंट पर चलने वाली क्वेरी के लिए इंडेक्स_बी का उपयोग करने के लिए क्वेरी प्लान को संकलित करना अधिक कुशल होगा। भले ही Index_B बड़ा है और स्कैन करने के लिए अधिक CPU चक्रों की आवश्यकता होगी, भौतिक पठन अतिरिक्त CPU चक्रों की तुलना में बहुत धीमा है इसलिए एक अधिक कुशल क्वेरी योजना भौतिक पढ़ने की संख्या को कम करती है।

यह तर्क केवल धारण करता है, और एक "इंडेक्स_बी का उपयोग करें" क्वेरी प्लान केवल "इंडेक्स_ए का उपयोग करें" क्वेरी प्लान से अधिक कुशल है, अगर इंडेक्स_बी ज्यादातर मेमोरी में रहता है, और इंडेक्स_ए ज्यादातर मेमोरी में नहीं रहता है। जैसे ही अधिकांश इंडेक्स_ए मेमोरी में होगा, "इंडेक्स_ए का उपयोग करें" क्वेरी योजना अधिक कुशल होगी, और "इंडेक्स_बी का उपयोग करें" क्वेरी योजना गलत विकल्प है।

ऐसी परिस्थितियाँ जब संकलित "इंडेक्स_बी का उपयोग करें" योजना लागत-आधारित "इंडेक्स_ए का उपयोग करें" योजना की तुलना में कम कुशल है (सामान्यीकरण):

  • Index_A और Index_B दोनों मेमोरी में हैं:संकलित योजना में लगभग तीन गुना अधिक समय लगेगा
  • कोई भी अनुक्रमणिका स्मृति निवासी नहीं है:संकलित योजना 3.5 गुना अधिक समय लेती है
  • Index_A स्मृति निवासी है और Index_B नहीं है:योजना द्वारा किए गए सभी भौतिक पठन बाहरी हैं, और इसमें 53 गुना अधिक समय लगेगा

सारांश

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

याद रखें, ऑप्टिमाइज़र का काम एक अच्छी योजना को तेजी से खोजना है, जरूरी नहीं कि सभी स्थितियों में से 100% के लिए एकल सर्वश्रेष्ठ योजना हो। मेरी राय में, SQL सर्वर ऑप्टिमाइज़र SQL सर्वर बफर पूल की वास्तविक सामग्री को अनदेखा करके सही काम करता है, और इसके बजाय एक क्वेरी योजना तैयार करने के लिए विभिन्न लागत नियमों पर निर्भर करता है जो कि सबसे अधिक कुशल होने की संभावना है समय ।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL में वर्णानुक्रम में ऑर्डर कैसे करें

  2. एक रेस्तरां वितरण डेटा मॉडल

  3. एक ऑनलाइन सर्वेक्षण के लिए एक डेटाबेस मॉडल। भाग 1

  4. Ubuntu 20.04 पर क्लिकहाउस को कैसे स्थापित और कॉन्फ़िगर करें?

  5. डुप्लिकेट डेटाबेस प्रश्नों को कम करने के लिए डेटाबेस कैशिंग का कोई रूप नहीं।