निष्पादन योजना में सूचित सूचकांक आकार और बफ़र्स की संख्या के बीच भारी बेमेल


10

समस्या

हमारे पास एक क्वेरी जैसी है

SELECT COUNT(1) 
  FROM article
  JOIN reservation ON a_id = r_article_id 
 WHERE r_last_modified < now() - '8 weeks'::interval 
   AND r_group_id = 1 
   AND r_status = 'OPEN';

जैसा कि यह एक टाइमआउट में चलता है (10 मिनट के बाद) अधिक बार नहीं, मैंने इस मुद्दे की जांच करने का फैसला किया।

EXPLAIN (ANALYZE, BUFFERS)उत्पादन इस तरह दिखता है:

 Aggregate  (cost=264775.48..264775.49 rows=1 width=0) (actual time=238960.290..238960.291 rows=1 loops=1)
   Buffers: shared hit=200483 read=64361 dirtied=666 written=8, temp read=3631 written=3617
   I/O Timings: read=169806.955 write=0.154
   ->  Hash Join  (cost=52413.67..264647.65 rows=51130 width=0) (actual time=1845.483..238957.588 rows=21644 loops=1)
         Hash Cond: (reservation.r_article_id = article.a_id)
         Buffers: shared hit=200483 read=64361 dirtied=666 written=8, temp read=3631 written=3617
         I/O Timings: read=169806.955 write=0.154
         ->  Index Scan using reservation_r_article_id_idx1 on reservation  (cost=0.42..205458.72 rows=51130 width=4) (actual time=34.035..237000.197 rows=21644 loops=1)
               Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
               Rows Removed by Filter: 151549
               Buffers: shared hit=200193 read=48853 dirtied=450 written=8
               I/O Timings: read=168614.105 write=0.154
         ->  Hash  (cost=29662.22..29662.22 rows=1386722 width=4) (actual time=1749.392..1749.392 rows=1386814 loops=1)
               Buckets: 32768  Batches: 8  Memory Usage: 6109kB
               Buffers: shared hit=287 read=15508 dirtied=216, temp written=3551
               I/O Timings: read=1192.850
               ->  Seq Scan on article  (cost=0.00..29662.22 rows=1386722 width=4) (actual time=23.822..1439.310 rows=1386814 loops=1)
                     Buffers: shared hit=287 read=15508 dirtied=216
                     I/O Timings: read=1192.850
 Total runtime: 238961.812 ms

अड़चन नोड स्पष्ट रूप से सूचकांक स्कैन है। तो आइए देखें सूचकांक की परिभाषा:

CREATE INDEX reservation_r_article_id_idx1 
    ON reservation USING btree (r_article_id)
 WHERE (r_status <> ALL (ARRAY['FULFILLED', 'CLOSED', 'CANCELED']));

आकार और पंक्ति संख्या

यह आकार ( \di+भौतिक फ़ाइल पर जाकर या रिपोर्ट किया गया) 36 एमबी है। चूंकि आरक्षण आमतौर पर ऊपर सूचीबद्ध सभी स्थितियों में केवल एक अपेक्षाकृत कम समय बिताता है, इसलिए बहुत अधिक अद्यतन हो रहा है, इसलिए सूचकांक काफी फूला हुआ है (लगभग 24 एमबी यहां बर्बाद हो गया है) - फिर भी, आकार अपेक्षाकृत छोटा है।

reservationमेज, आकार में 3.8 जीबी के बारे में है लगभग 40 लाख पंक्तियां हैं। अभी तक बंद नहीं किए गए आरक्षणों की संख्या लगभग 170,000 है (सटीक संख्या ऊपर सूचकांक स्कैन नोड में बताई गई है)।

अब आश्चर्य: सूचकांक स्कैन रिपोर्ट में बड़ी मात्रा में बफ़र्स (यानी, 8 केबी पृष्ठ) प्राप्त होते हैं:

Buffers: shared hit=200193 read=48853 dirtied=450 written=8

कैश और डिस्क (या ओएस कैश) से पढ़े गए नंबर 1.9 जीबी तक जुड़ते हैं!

सबसे बुरी स्थिति

दूसरी ओर, सबसे खराब स्थिति, जब प्रत्येक टपल तालिका के एक अलग पृष्ठ पर बैठता है, तो विज़िट करने का हिसाब होगा (21644 + 151549) + 4608 पृष्ठ (तालिका से प्राप्त कुल पंक्तियाँ और भौतिक से अनुक्रमणिका पृष्ठ संख्या) आकार)। यह अभी भी केवल 180,000 से कम है - मनाया लगभग 250,000 से नीचे।

दिलचस्प (और शायद महत्वपूर्ण) यह है कि डिस्क पढ़ने की गति लगभग 2.2 एमबी / एस है, जो काफी सामान्य है, मुझे लगता है।

तो क्या?

क्या किसी को इस बात का अंदाजा है कि यह विसंगति कहां से आ सकती है?

नोट: स्पष्ट होने के लिए, हमारे पास यह विचार है कि यहां क्या सुधार / परिवर्तन करना है, लेकिन मैं वास्तव में मुझे प्राप्त संख्याओं को समझना चाहता हूं - यह वही है जो सवाल है।

अपडेट: कैशिंग या माइक्रोवैक्यूमिंग के प्रभाव की जाँच करना

जैजेस के जवाब के आधार पर , मैंने जाँच की है कि क्या होता है जब मैं सीधे उसी क्वेरी को फिर से सीधे चलाता हूं। प्रभावित बफ़रों की संख्या वास्तव में नहीं बदलती है। (ऐसा करने के लिए, मैंने क्वेरी को इसके नंगे न्यूनतम पर सरलीकृत किया जो अभी भी समस्या दिखाता है।) यह वही है जो मैं पहले रन से देखता हूं:

 Aggregate  (cost=240541.52..240541.53 rows=1 width=0) (actual time=97703.589..97703.590 rows=1 loops=1)
   Buffers: shared hit=413981 read=46977 dirtied=56
   I/O Timings: read=96807.444
   ->  Index Scan using reservation_r_article_id_idx1 on reservation  (cost=0.42..240380.54 rows=64392 width=0) (actual time=13.757..97698.461 rows=19236 loops=1)
         Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
         Rows Removed by Filter: 232481
         Buffers: shared hit=413981 read=46977 dirtied=56
         I/O Timings: read=96807.444
 Total runtime: 97703.694 ms

और दूसरे के बाद:

 Aggregate  (cost=240543.26..240543.27 rows=1 width=0) (actual time=388.123..388.124 rows=1 loops=1)
   Buffers: shared hit=460990
   ->  Index Scan using reservation_r_article_id_idx1 on reservation  (cost=0.42..240382.28 rows=64392 width=0) (actual time=0.032..385.900 rows=19236 loops=1)
         Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
         Rows Removed by Filter: 232584
         Buffers: shared hit=460990
 Total runtime: 388.187 ms

1
शायद अप्रासंगिक लेकिन क्या आपको इसमें शामिल होने की आवश्यकता है article? इसमें शामिल सभी कॉलम reservationटेबल से हैं और माना जाता है कि एफके है, परिणाम समान होना चाहिए।
ypercube y

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

1
मुझे जोड़ने दें कि ज्वाइन को हटाने से बहुत बड़ा फर्क नहीं पड़ता है - ओवरब्लॉक इंडेक्स स्कैन वहां रहता है।
dezso

टोस्ट टेबल एक्सेस? हालाँकि मुझे संदेह है कि आपके द्वारा दिखाए गए किसी भी कॉलम में टोस्ट होगा। यदि आपके पास परीक्षण उद्देश्यों के लिए डेटाबेस का एक निष्क्रिय क्लोन है, तो आप उस pg_stat_reset()पर दौड़ सकते हैं , और फिर क्वेरी को चला सकते हैं, और फिर यह देखने के pg_statio_user_tablesलिए देख सकते हैं कि यह ब्लॉक कहां है।
जेजेन्स

जवाबों:


4

मुझे लगता है कि यहां कुंजी बहुत सारे अपडेट है, और इंडेक्स पर ब्लोट है।

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

सूचकांक को स्कैन करते समय, इसे इन पंक्तियों पर जाना होगा, और फिर नोटिस वे अब दिखाई नहीं देते हैं, इसलिए उन्हें अनदेखा करता है। explain (analyze,buffers)बयान को स्पष्ट रूप से इस गतिविधि पर रिपोर्ट नहीं करता, इन पंक्तियों का निरीक्षण करने की प्रक्रिया में पढ़ने / हिट बफ़र्स की गिनती के माध्यम से छोड़कर।

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

आप VACUUMतालिका को अधिक बार भी कर सकते हैं , जो कि आंशिक रूप से बाहर नहीं, बल्कि तालिका से मृत टुपल्स को भी साफ कर देगा। सामान्य तौर पर, एक उच्च-टर्न-ओवर आंशिक सूचकांक वाली तालिकाओं को डिफ़ॉल्ट स्तर की तुलना में अधिक आक्रामक वैक्यूम से लाभ होने की संभावना है।


कृपया मेरा संपादन देखें - मेरे लिए, यह कैशिंग की तरह दिखता है, न कि माइक्रोवैक्यूमिंग।
dezso

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

आज जैसी वे दिख रही हैं, वैसी ही पूरी योजनाएं जोड़ें। शुक्रवार से प्रभावित बफर संख्या बहुत बढ़ गई, जैसा कि पंक्ति की गिनती थी।
dezso

क्या आपके पास लंबे समय तक रहने वाला लेनदेन लटका हुआ है? यदि ऐसा है, तो यह संभव है कि सूचकांक स्कैन अभी भी उन पंक्तियों को ट्रैक कर रहा है जो इसे दिखाई नहीं दे रहे हैं (जो अतिरिक्त बफर हिट का कारण बनता है), लेकिन यह उन्हें अभी तक माइक्रोवैक्यूम नहीं कर सकता है क्योंकि वे किसी और के साथ दिखाई दे सकते हैं। स्नैपशॉट।
जेजेन्स

मेरे पास कोई नहीं है - विशिष्ट लेनदेन एक सेकंड से भी कम समय लेता है। कभी-कभी कुछ सेकंड, लेकिन लंबे समय तक नहीं।
dezso
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.