समस्या
हमारे पास एक क्वेरी जैसी है
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
pg_stat_reset()
पर दौड़ सकते हैं , और फिर क्वेरी को चला सकते हैं, और फिर यह देखने के pg_statio_user_tables
लिए देख सकते हैं कि यह ब्लॉक कहां है।
article
? इसमें शामिल सभी कॉलमreservation
टेबल से हैं और माना जाता है कि एफके है, परिणाम समान होना चाहिए।