Yürütme planında bildirilen dizin boyutu ile arabellek sayısı arasında büyük uyumsuzluk


10

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.

reservationTablo 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

1
Muhtemelen alakasız, ancak katılmak için ihtiyacınız var articlemı? İlgili tüm sütunlar reservationtablodan görünüyor ve (FK) varsayalım, sonuç aynı olmalı.
ypercubeᵀᴹ

Bu çok iyi bir soru. Haklısınız, gerekli değil - bu, başka bir ekip tarafından izlemede kullanılan bir sorgu. Yine de, en azından sorgu planına bakarak, her şey sadece bu kötü endeks taraması için dekorasyon :)
dezso

1
Eklemenin kaldırılmasının büyük bir fark yaratmadığını da ekleyeyim - aşırı şişirilmiş dizin taraması orada kalır.
dezso

Tost masasına erişim? Gösterdiğin sütunlardan herhangi birinden şüphe etsem de kızardı. Sınama amacıyla veritabanının boş bir klonuna sahipseniz, pg_stat_reset()üzerinde çalışabilir ve sorguyu çalıştırabilir ve ardından pg_statio_user_tablesblokları nerede ilişkilendirdiğini görmek için içeriye bakabilirsiniz .
jjanes

Yanıtlar:


4

Buradaki anahtarın çok fazla güncelleme olduğunu ve dizindeki şişkinlik olduğunu düşünüyorum.

Dizin, tablodaki artık 'canlı' olmayan satırlara işaretçiler içerir. Bunlar güncellenmiş satırların eski sürümleridir. Eski bir anlık görüntü ile sorguları tatmin etmek için eski satır sürümleri bir süre tutulur ve daha sonra bir süre daha saklanır, çünkü kimse bunları gerektiğinden daha sık kaldırma işini yapmak istemez.

Dizini tararken, bu satırları ziyaret etmeli ve sonra artık görünmediklerini fark etmelidir, bu yüzden onları yok sayar. explain (analyze,buffers)Açıklamada söz konusu satırları teftiş sürecinde / hit okunan tamponların sayma yoluyla hariç, açıkça bu faaliyet üzerinde bildirmez.

Btrees için bazı "mikrodamar" kodu vardır, böylece tarama tekrar dizine geri döndüğünde, izlediği işaretçinin artık canlı olmadığını hatırlar ve dizinde ölü olarak işaretler. Bu şekilde çalıştırılan bir sonraki benzer sorgunun onu tekrar takip etmesi gerekmez. Dolayısıyla, aynı sorguyu tekrar çalıştırırsanız, muhtemelen arabellek erişimlerinin öngördüğünüze daha yakın düştüğünü görürsünüz.

Ayrıca VACUUM, sadece kısmi dizinden değil, ölü kaplumbağaları da masanın kendisinden temizleyecek olan tabloyu daha sık yapabilirsiniz . Genel olarak, yüksek dönüşlü kısmi endeksli tabloların varsayılan seviyeden daha agresif vakumdan faydalanması muhtemeldir.


Lütfen düzenlememe bakın - bana göre, mikrovakumlama değil, önbelleğe alma gibi görünüyor.
dezso

Yeni sayılarınız eskilerinizden çok farklıdır (kabaca iki kat), bu nedenle, gerçek satırlar ve dizin taraması için filtrelenen satırlar için yeni sayıları görmeden ne anlama geldiğini yorumlamak zordur.
jjanes

Planların tamamı bugün göründükleri şekilde eklendi. Etkilenen arabellek sayısı ve satır sayımları Cuma gününden bu yana çok arttı.
dezso

Uzun süredir devam eden işlemleriniz var mı? Öyleyse, dizin taramasının hala görünmeyen satırları izlemesi mümkündür (bu da ekstra arabellek isabetlerine neden olur), ancak daha eski olan başka bir kişi tarafından görülebileceği için henüz mikro-vakumlama yapamaz. enstantane fotoğraf.
jjanes

Hiç yok - tipik işlem bir saniyeden az sürer. Bazen birkaç saniye, ancak daha uzun değil.
dezso
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.