Sorun
Şunun gibi bir sorgumuz var:
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';
Zaman aşımına (10 dakika sonra) rastlanmadığından daha sık girdiği için, sorunu araştırmaya karar verdim.
EXPLAIN (ANALYZE, BUFFERS)
Çıktı aşağıdaki gibidir:
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
Darboğaz düğümü elbette dizin taramasıdır. Şimdi dizin tanımını görelim:
CREATE INDEX reservation_r_article_id_idx1
ON reservation USING btree (r_article_id)
WHERE (r_status <> ALL (ARRAY['FULFILLED', 'CLOSED', 'CANCELED']));
Boyutlar ve satır numaraları
Boyutu ( \di+
fiziksel dosyayı ziyaret ederek veya ziyaret ederek) 36 MB'dir. Rezervasyonlar genellikle yukarıda listelenmeyen tüm durumlarda sadece nispeten kısa bir zaman harcadığından, güncelleme çok şey var, bu nedenle dizin oldukça şişirilmiş (burada yaklaşık 24 MB boşa harcanıyor) - yine de, boyut nispeten küçük.
reservation
Tablo 40 milyon satır içeren, büyüklüğü 3.8 GB hakkındadır. Henüz kapalı olmayan rezervasyon sayısı yaklaşık 170.000'dir (tam sayı yukarıdaki indeks tarama düğümünde rapor edilir).
Şimdi sürpriz: dizin tarama raporları büyük miktarda tampon (yani 8 kb sayfa) getiriyor:
Buffers: shared hit=200193 read=48853 dirtied=450 written=8
Önbellekten ve diskten (veya OS önbelleğinden) okunan sayılar 1,9 GB'a kadar çıkar!
En kötü durum senaryosu
Öte yandan, en kötü senaryo, her grup tablonun farklı bir sayfasında oturduğunda, (21644 + 151549) + 4608 sayfayı (tablodan getirilen toplam satır sayısı artı fiziksel sayfadan dizin sayfası numarasını) boyut). Bu hala sadece 180.000'in altında - gözlemlenen yaklaşık 250.000'in çok altında.
İlginç (ve belki de önemli), disk okuma hızının 2.2 MB / s civarında olması, sanırım oldukça normal.
Ne olmuş yani?
Bu tutarsızlığın nereden gelebileceği hakkında bir fikri olan var mı?
Not: Açıkça söylemek gerekirse, burada neyi iyileştireceğimiz / değiştireceğimiz konusunda fikirlerimiz var, ancak gerçekten sahip olduğum sayıları anlamak istiyorum - sorunun konusu bu.
Güncelleme: önbellekleme veya mikro-vakumlamanın etkisini kontrol etme
Dayanarak jjanes cevabı , ben hemen aynı sorguyu yeniden çalıştırın ne olur kontrol ettik. Etkilenen arabelleklerin sayısı gerçekten değişmez. (Bunu yapmak için, sorunu hala gösteren çıplak asgari sorgu basitleştirilmiş.) Bu ilk çalıştırmadan gördüklerim:
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
ve ikincisinden sonra:
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()
üzerinde çalışabilir ve sorguyu çalıştırabilir ve ardından pg_statio_user_tables
blokları nerede ilişkilendirdiğini görmek için içeriye bakabilirsiniz .
article
mı? İlgili tüm sütunlarreservation
tablodan görünüyor ve (FK) varsayalım, sonuç aynı olmalı.