पोस्टग्रेज EXPLAIN लागत को समझना
EXPLAIN
Postgres क्वेरी के प्रदर्शन को समझने के लिए बहुत उपयोगी है। यह किसी दिए गए कथन के लिए PostgreSQL क्वेरी प्लानर द्वारा उत्पन्न निष्पादन योजना देता है। EXPLAIN
कमांड निर्दिष्ट करता है कि किसी स्टेटमेंट में संदर्भित टेबल को इंडेक्स स्कैन या अनुक्रमिक स्कैन का उपयोग करके खोजा जाएगा या नहीं।
EXPLAIN
. के आउटपुट की समीक्षा करते समय कुछ पहली चीज़ें जो आप देखेंगे कमांड लागत के आंकड़े हैं, इसलिए यह आश्चर्य होना स्वाभाविक है कि उनका क्या मतलब है, उनकी गणना कैसे की जाती है और उनका उपयोग कैसे किया जाता है।
संक्षेप में, PostgreSQL क्वेरी प्लानर यह अनुमान लगा रहा है कि स्टार्टअप लागत और प्रत्येक ऑपरेशन के लिए कुल लागत दोनों के साथ क्वेरी में कितना समय लगेगा (एक मनमानी इकाई में)। उस पर और बाद में। जब किसी क्वेरी को निष्पादित करने के लिए उसके पास कई विकल्प होते हैं, तो वह इन लागतों का उपयोग सबसे सस्ता, और इसलिए सबसे तेज़, विकल्प चुनने के लिए करता है।
लागत किस इकाई में है?
लागत एक मनमानी इकाई में हैं। एक आम गलतफहमी यह है कि वे मिलीसेकंड या समय की किसी अन्य इकाई में हैं, लेकिन ऐसा नहीं है।
लागत इकाइयाँ (डिफ़ॉल्ट रूप से) 1.0 इकाइयों (seq_page_cost
) की लागत वाले एकल अनुक्रमिक पृष्ठ से जुड़ी होती हैं। ) संसाधित की गई प्रत्येक पंक्ति में 0.01 (cpu_tuple_cost
जुड़ती है ), और पढ़ा गया प्रत्येक गैर-अनुक्रमिक पृष्ठ 4.0 जोड़ता है (random_page_cost
) इस तरह के और भी कई स्थिरांक हैं, जो सभी विन्यास योग्य हैं। वह अंतिम एक विशेष रूप से सामान्य उम्मीदवार है, कम से कम आधुनिक हार्डवेयर पर। हम उस पर थोड़ा और गौर करेंगे।
स्टार्टअप लागत
cost=
. के बाद आपको सबसे पहले दिखाई देने वाले नंबर "स्टार्टअप लागत" के रूप में जाना जाता है। यह एक अनुमान है कि पहली पंक्ति लाने . में कितना समय लगेगा . जैसे, किसी ऑपरेशन की स्टार्टअप लागत में उसके बच्चों की लागत शामिल होती है।
अनुक्रमिक स्कैन के लिए, स्टार्टअप लागत आम तौर पर शून्य के करीब होगी, क्योंकि यह सीधे पंक्तियों को लाना शुरू कर सकता है। सॉर्ट ऑपरेशन के लिए, यह अधिक होगा क्योंकि पंक्तियों को वापस करना शुरू करने से पहले काम का एक बड़ा हिस्सा किया जाना चाहिए।
एक उदाहरण देखने के लिए, आइए 1000 उपयोगकर्ता नामों के साथ एक साधारण परीक्षण तालिका बनाएं:
CREATE TABLE users ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, username text NOT NULL); INSERT INTO users (username) SELECT 'person' || n FROM generate_series(1, 1000) AS n; ANALYZE users;
आइए कुछ कार्यों के साथ एक साधारण क्वेरी योजना पर एक नज़र डालें:
EXPLAIN SELECT * FROM users ORDER BY username; QUERY PLAN | --------------------------------------------------------------+ Sort (cost=66.83..69.33 rows=1000 width=17) | Sort Key: username | -> Seq Scan on users (cost=0.00..17.00 rows=1000 width=17)|
उपरोक्त क्वेरी योजना में, जैसा कि अपेक्षित था, Seq Scan
. के लिए अनुमानित विवरण निष्पादन लागत है 0.00
, और Sort
. के लिए है 66.83
।
कुल लागत
स्टार्टअप लागत और दो बिंदुओं के बाद दूसरा लागत आंकड़ा "कुल लागत" के रूप में जाना जाता है। यह एक अनुमान है कि सभी पंक्तियों को वापस करने में कितना समय लगेगा ।
आइए उस उदाहरण क्वेरी योजना को फिर से देखें:
QUERY PLAN | --------------------------------------------------------------+ Sort (cost=66.83..69.33 rows=1000 width=17) | Sort Key: username | -> Seq Scan on users (cost=0.00..17.00 rows=1000 width=17)|
हम देख सकते हैं कि Seq Scan
. की कुल लागत ऑपरेशन है 17.00
. Sort
के लिए ऑपरेशन 69.33 है, जो इसकी स्टार्टअप लागत (उम्मीद के मुताबिक) से ज्यादा नहीं है।
कुल लागत में आमतौर पर उनके पूर्ववर्ती संचालन की लागत शामिल होती है। उदाहरण के लिए, ऊपर क्रमबद्ध संचालन की कुल लागत में Seq स्कैन की लागत शामिल है।
एक महत्वपूर्ण अपवाद है LIMIT
खंड, जिसका उपयोग योजनाकार यह अनुमान लगाने के लिए करता है कि क्या यह जल्दी निरस्त हो सकता है। यदि इसे केवल पंक्तियों की एक छोटी संख्या की आवश्यकता होती है, जिसके लिए स्थितियां सामान्य हैं, तो यह गणना कर सकता है कि एक आसान स्कैन विकल्प सस्ता है (यह तेज़ होने की संभावना है)।
उदाहरण के लिए:
EXPLAIN SELECT * FROM users LIMIT 1; QUERY PLAN | --------------------------------------------------------------+ Limit (cost=0.00..0.02 rows=1 width=17) | -> Seq Scan on users (cost=0.00..17.00 rows=1000 width=17)|
जैसा कि आप देख सकते हैं, Seq स्कैन नोड पर रिपोर्ट की गई कुल लागत अभी भी 17.00 है, लेकिन सीमा संचालन की पूरी लागत 0.02 बताई गई है। ऐसा इसलिए है क्योंकि योजनाकार को उम्मीद है कि उसे 1000 में से केवल 1 पंक्ति को संसाधित करना होगा, इसलिए इस मामले में लागत कुल का 1000वां होने का अनुमान है।
लागतों की गणना कैसे की जाती है
इन लागतों की गणना करने के लिए, पोस्टग्रेज क्वेरी प्लानर डेटाबेस की सामग्री के बारे में स्थिरांक (जिनमें से कुछ हमने पहले ही देखा है) और मेटाडेटा दोनों का उपयोग करता है। मेटाडेटा को अक्सर "आंकड़े" के रूप में संदर्भित किया जाता है।
आंकड़े ANALYZE
. के माध्यम से एकत्रित किए जाते हैं (EXPLAIN
. के साथ भ्रमित होने की नहीं एक ही नाम का पैरामीटर), और pg_statistic
. में संग्रहीत . वे ऑटोवैक्यूम के हिस्से के रूप में भी स्वचालित रूप से ताज़ा हो जाते हैं।
इन आँकड़ों में कई बहुत उपयोगी चीज़ें शामिल हैं, जैसे मोटे तौर पर प्रत्येक तालिका में पंक्तियों की संख्या, और प्रत्येक स्तंभ में सबसे सामान्य मान क्या हैं।
आइए पहले के समान क्वेरी डेटा का उपयोग करके एक सरल उदाहरण देखें:
EXPLAIN SELECT count(*) FROM users; QUERY PLAN | -------------------------------------------------------------+ Aggregate (cost=19.50..19.51 rows=1 width=8) | -> Seq Scan on users (cost=0.00..17.00 rows=1000 width=0)|
हमारे मामले में, योजनाकार के आंकड़ों ने सुझाव दिया कि तालिका के लिए डेटा 7 पृष्ठों (या ब्लॉक) के भीतर संग्रहीत किया गया था, और 1000 पंक्तियों को वापस कर दिया जाएगा। लागत पैरामीटर seq_page_cost
, cpu_tuple_cost
, और cpu_operator_cost
1
. के अपने डिफ़ॉल्ट पर छोड़ दिए गए थे , 0.01
, और 0.0025
क्रमशः।
जैसे, Seq स्कैन की कुल लागत की गणना इस प्रकार की गई:
Total cost of Seq Scan = (estimated sequential page reads * seq_page_cost) + (estimated rows returned * cpu_tuple_cost) = (7 * 1) + (1000 * 0.01) = 7 + 10.00 = 17.00
और कुल के रूप में:
Total cost of Aggregate = (cost of Seq Scan) + (estimated rows processed * cpu_operator_cost) + (estimated rows returned * cpu_tuple_cost) = (17.00) + (1000 * 0.0025) + (1 * 0.01) = 17.00 + 2.50 + 0.01 = 19.51
नियोजक कैसे लागतों का उपयोग करता है
चूंकि हम जानते हैं कि पोस्टग्रेज सबसे कम कुल लागत के साथ क्वेरी प्लान चुनेंगे, हम इसका उपयोग अपने द्वारा किए गए विकल्पों को समझने की कोशिश करने के लिए कर सकते हैं। उदाहरण के लिए, यदि कोई क्वेरी उस अनुक्रमणिका का उपयोग नहीं कर रही है जिसकी आप अपेक्षा करते हैं, तो आप enable_seqscan
जैसी सेटिंग का उपयोग कर सकते हैं कुछ प्रश्न योजना विकल्पों को व्यापक रूप से हतोत्साहित करने के लिए। इस बिंदु तक, आपको यह सुनकर आश्चर्य नहीं होना चाहिए कि इस तरह की सेटिंग्स लागतों को बढ़ाकर काम करती हैं!
पंक्ति संख्याएँ लागत अनुमान का एक अत्यंत महत्वपूर्ण हिस्सा हैं। उनका उपयोग विभिन्न जॉइन ऑर्डर के अनुमानों की गणना करने, एल्गोरिदम में शामिल होने, स्कैन प्रकार और बहुत कुछ करने के लिए किया जाता है। पंक्ति लागत अनुमान जो बहुत अधिक हैं, लागत अनुमान बहुत अधिक हो सकते हैं, जिसके परिणामस्वरूप अंततः एक उप-इष्टतम योजना विकल्प बनाया जा सकता है।
क्वेरी प्लान प्राप्त करने के लिए EXPLAIN ANALYZE का उपयोग करना
जब आप PostgreSQL में SQL स्टेटमेंट लिखते हैं, तो ANALYZE
कमांड प्रश्नों को अनुकूलित करने, उन्हें तेज और अधिक कुशल बनाने की कुंजी है। क्वेरी योजना और पोस्टग्रेएसक्यूएल अनुमान प्रदर्शित करने के अलावा, EXPLAIN ANALYZE
विकल्प क्वेरी करता है (UPDATE
से सावधान रहें) और DELETE
!), और निष्पादन प्रक्रिया में प्रत्येक चरण के लिए वास्तविक निष्पादन समय और पंक्ति गणना संख्या दिखाता है। SQL प्रदर्शन की निगरानी के लिए यह आवश्यक है।
आप EXPLAIN ANALYZE
. का उपयोग कर सकते हैं प्रत्येक ऑपरेशन द्वारा लौटाई गई वास्तविक पंक्तियों के साथ पंक्तियों की अनुमानित संख्या की तुलना करने के लिए।
आइए फिर से उसी डेटा का उपयोग करके एक उदाहरण देखें:
QUERY PLAN | -----------------------------------------------------------------------------------------------------------+ Sort (cost=66.83..69.33 rows=1000 width=17) (actual time=20.569..20.684 rows=1000 loops=1) | Sort Key: username | Sort Method: quicksort Memory: 102kB | -> Seq Scan on users (cost=0.00..17.00 rows=1000 width=17) (actual time=0.048..0.596 rows=1000 loops=1)| Planning Time: 0.171 ms | Execution Time: 20.793 ms |
हम देख सकते हैं कि कुल निष्पादन लागत अभी भी 69.33 है, जिसमें से अधिकांश सॉर्ट ऑपरेशन है, और 17.00 अनुक्रमिक स्कैन से आ रहा है। ध्यान दें कि क्वेरी निष्पादन समय केवल 21ms से कम है।
अनुक्रमिक स्कैन बनाम अनुक्रमणिका स्कैन
अब, संपूर्ण तालिका के उस महंगे प्रकार से बचने की कोशिश करने के लिए एक अनुक्रमणिका जोड़ें:
CREATE INDEX people_username_idx ON users (username); EXPLAIN ANALYZE SELECT * FROM users ORDER BY username; QUERY PLAN | ---------------------------------------------------------------------------------------------------------------------------------+ Index Scan using people_username_idx on users (cost=0.28..28.27 rows=1000 width=17) (actual time=0.052..1.494 rows=1000 loops=1)| Planning Time: 0.186 ms | Execution Time: 1.686 ms |
जैसा कि आप देख सकते हैं, क्वेरी प्लानर ने अब एक इंडेक्स स्कैन चुना है, क्योंकि उस प्लान की कुल लागत 28.27 (69.33 से कम) है। ऐसा लगता है कि अनुक्रमिक स्कैन की तुलना में अनुक्रमणिका स्कैन अधिक कुशल था, क्योंकि क्वेरी निष्पादन समय अब केवल 2ms से कम है।
नियोजक को अधिक सटीक अनुमान लगाने में सहायता करना
हम योजनाकार को दो तरीकों से अधिक सटीक अनुमान लगाने में मदद कर सकते हैं:
- बेहतर आंकड़े इकट्ठा करने में उसकी मदद करें
- गणना के लिए उपयोग किए जाने वाले स्थिरांक को ट्यून करें
किसी तालिका में डेटा में बड़े परिवर्तन के बाद आँकड़े विशेष रूप से खराब हो सकते हैं। जैसे, तालिका में बहुत सारा डेटा लोड करते समय, आप मैन्युअल ANALYZE
चलाकर Postgres को बाहर निकालने में मदद कर सकते हैं इस पर। आंकड़े भी एक प्रमुख संस्करण अपग्रेड पर कायम नहीं रहते हैं, इसलिए ऐसा करने का यह एक और महत्वपूर्ण समय है।
स्वाभाविक रूप से, समय के साथ टेबल भी बदलते हैं, इसलिए ऑटोवैक्यूम सेटिंग्स को ट्यून करना यह सुनिश्चित करने के लिए कि यह आपके कार्यभार के लिए पर्याप्त रूप से बार-बार चलता है, बहुत मददगार हो सकता है।
यदि आपको विषम वितरण वाले कॉलम के लिए खराब अनुमानों से परेशानी हो रही है, तो आपको ALTER TABLE SET STATISTICS
का उपयोग करके पोस्टग्रेज द्वारा एकत्रित की जाने वाली जानकारी की मात्रा बढ़ाने से लाभ हो सकता है। कमांड, या यहां तक कि default_statistics_target
पूरे डेटाबेस के लिए।
खराब अनुमानों का एक अन्य सामान्य कारण यह है कि, डिफ़ॉल्ट रूप से, पोस्टग्रेज़ यह मान लेंगे कि दो कॉलम स्वतंत्र हैं। आप इसे विस्तारित आंकड़ों के माध्यम से एक ही तालिका से दो स्तंभों पर सहसंबंध डेटा एकत्र करने के लिए कहकर इसे ठीक कर सकते हैं।
निरंतर ट्यूनिंग के मोर्चे पर, ऐसे बहुत से पैरामीटर हैं जिन्हें आप अपने हार्डवेयर के अनुरूप ट्यून कर सकते हैं। यह मानते हुए कि आप SSD पर चल रहे हैं, आप कम से कम random_page_cost
की अपनी सेटिंग को ट्यून करना चाहेंगे . यह डिफ़ॉल्ट रूप से 4 हो जाता है, जो seq_page_cost
. से 4 गुना अधिक महंगा है हमने पहले देखा। यह अनुपात कताई डिस्क पर समझ में आता है, लेकिन एसएसडी पर यह यादृच्छिक I/O को बहुत अधिक दंडित करता है। इस तरह की सेटिंग 1 के करीब या 1 और 2 के बीच, अधिक समझ में आ सकती है। स्केलग्रिड में, हम डिफ़ॉल्ट रूप से 1.
क्या मैं क्वेरी प्लान से लागत निकाल सकता हूं?
ऊपर बताए गए कई कारणों से, अधिकांश लोग EXPLAIN
. चलाते समय लागत छोड़ देते हैं . हालाँकि, यदि आप चाहें, तो आप COSTS
. का उपयोग करके उन्हें बंद कर सकते हैं पैरामीटर।
EXPLAIN (COSTS OFF) SELECT * FROM users LIMIT 1; QUERY PLAN | -----------------------+ Limit | -> Seq Scan on users|
निष्कर्ष
पुन:कैप करने के लिए, क्वेरी योजनाओं में लागत पोस्टग्रेज़ का अनुमान है कि एक मनमानी इकाई में SQL क्वेरी को कितना समय लगेगा।
यह कुछ विन्यास योग्य स्थिरांक और इसके द्वारा एकत्रित किए गए कुछ आंकड़ों के आधार पर न्यूनतम समग्र लागत वाली योजना को चुनता है।
इन लागतों का अधिक सटीक अनुमान लगाने में मदद करना, अच्छे विकल्प बनाने में मदद करने के लिए और अपने प्रश्नों को बेहतर बनाए रखने के लिए बहुत महत्वपूर्ण है।
|