İçeriğe geç
Muhammet Şafak
en

Partial index on beş dakikada üç yüz seksen kat şişti — ve autovacuum bir kez bile gelmedi

Sürekli churn altındaki bir kuyruk tablosunda partial index'in küçüklüğü kalıcı mı, ve varsayılan autovacuum ayarları ona yetişiyor mu?

Bulgu

Canlı küme beş bin satırda sabit dururken partial index 0,1 MB'dan 38,2 MB'a çıktı — üç yüz seksen kat. Küçüklüğü canlı satır sayısından geliyor, şişme hızı iş hacminden, ve ikisi arasında hiçbir bağ yok. Composite index oransal olarak daha az şişti (%42) ama mutlak olarak daha çok (+126 MB) ve şişerken belleğe sığmayı bıraktı: gecikmesi 0,52 ms'den 61 saniyeye çıktı, kuyruğu 126 bine tırmandı. On beş dakikada 1,75 milyon ölü satır birikti ve autovacuum **bir kez bile koşmadı** — varsayılan eşik tablonun tamamına göre ölçekleniyor (50 + 0,2 × 10 milyon ≈ 2 milyon), churn ise küçük canlı kümede oluyor.

Partial index, 15 dakikada
0,1 → 38,2 MB 380×
Composite index, aynı sürede
301 → 427 MB +%42
Autovacuum koşma sayısı
0
Composite gecikmesi, 900. saniye
61.533 ms

Yöntem

Partial index ölçümüyle aynı tezgâh, aynı Postgres 17 ayarları, aynı 10 milyon ölü + 5.000 canlı satırlık tablo. Üç fark var, üçü de bu soruyu sorabilmek için zorunlu. Tüketici satırı `pending`'e geri koymuyor, `done` işaretliyor — sınanan iddia satırın index'ten DÜŞMESİYLE ilgili ve hiç düşmeyen satırda ölçülemez. Yanında sabit varış hızında (2.000/sn) bir üretici koşuyor, yani tablo önceki kaydın eksik ilan etmek zorunda kaldığı insert trafiğini de görüyor. Ve talep, `\gset` yerine alt sorgulu `UPDATE` biçiminde: kısıtsız bir tüketici kuyruğu bir saniyenin altında boşaltıyor ve `\gset` boş sonuçta istemciyi öldürüyor. Tüketici de üretici hızına bağlandı, böylece kuyruk derinliği sabit kalıyor — ve sabit kaldığı örneklenerek doğrulanıyor, varsayılmıyor. On beş saniyede bir tablo boyutu, index boyutu, kuyruk derinliği, ölü satır sayısı ve autovacuum sayaçları kaydedildi; strateji başına 60 örnek.

Yüksek güven Tekrarlı ölçüm, denetimli ortam, ham veri paylaşıldı.
Ölçüm tarihi

dün ölçüldü

Yayın

Ortam

Postgres
17-alpine · shared_buffers 1 GB · autovacuum varsayılan ayarlarda
Tablo
10M ölü + 5.000 canlı satır · 1.421 MB başlangıç
Yük
üretici 2.000/sn sabit · tüketici 8 istemci, aynı hızda
Süre
strateji başına 900 sn · 15 saniyede bir örnek · 60 örnek
Donanım
Apple M4 Pro · 12 çekirdek · 24 GB · Docker Desktop 29.7.2

Teknolojiler

PostgreSQL SQL pgbench Docker

Tekrarlamak için

DURATION=900 ./bench/endurance.sh

Partial index ölçümü otuz saniyelik pencerelerle çalıştı ve sınırlar kutusunda şunu yazdı: “30 saniyelik koşular autovacuum’un uzun vadeli etkisini ölçmeye yetmez, bu ayrı bir kayıt konusu.” Bu o kayıt.

Sınanan iddia, Sor Bakalım cevabının tek ölçülmemiş maddesiydi: “Bir satır pending’den done’a döndüğünde partial index’ten düşer — bu iyi. Ama yoğun update trafiği bloat üretebilir; autovacuum’un sağlıklı çalışması önemli. İyi haber: index küçük olduğu için vacuum’u da ucuzdur.”

Bloat eğrisi

Index boyutu, sürekli churn altında

Kuyruk derinliği koşu boyunca beş bin satır civarında sabit. Büyüyen tek şey ölü index girdileri.

  • partial
  • composite

MB düşük olan iyi Kaynak: pg_relation_size, 15 saniyede bir örnek, bench/endurance.sh

Veri tablosu
pg_relation_size, 15 saniyede bir örnek, bench/endurance.sh
Seri 0 sn135286436587738888
partial 0,1 MB5,9 MB12,4 MB18,8 MB25,3 MB31,7 MB38,2 MB
composite 301 MB321 MB344 MB366 MB388 MB409 MB427 MB

Grafik tarayıcıda çizilir; aşağıdaki tablo aynı veriyi taşır.

Partial index üç yüz seksen kat büyüdü. Composite %42. Mutlak artış composite’te daha fazla (+126 MB), oransal olarak partial’da karşılaştırılamaz.

Sebep tek cümlede duruyor: pending → done geçişi satırı partial index’ten düşürüyor, ama ölü girdi vacuum gelene kadar orada kalıyor. Yani index’in küçüklüğü canlı satır sayısından, şişme hızı iş hacminden geliyor — ve ikisi arasında hiçbir bağ yok. Beş bin satırlık bir kuyruk, saniyede iki bin iş işlerken, on beş dakikada otuz sekiz megabaytlık ölü girdi biriktiriyor.

Autovacuum hiç gelmedi

On beş dakikada 1.753.949 ölü satır birikti. Autovacuum sayacı: 0.

Aritmetik acımasız:

eşik = autovacuum_vacuum_threshold + scale_factor × canlı satır
     = 50 + 0,2 × 10.005.000
     ≈ 2.001.050 ölü satır

Eşiğin hemen altında kaldık. Varsayılan ayarlarla bu tablo autovacuum’u yaklaşık on yedi dakikada bir tetikleyecek ve arada index’ler serbestçe şişecek.

Asıl mesele oran değil, ölçekleme yönü: eşik tablonun tamamına göre büyüyor, churn ise küçük canlı kümede oluyor ve tablo büyüdükçe hızlanmıyor. Yani tablo ne kadar büyükse autovacuum o kadar geç geliyor.

Şişen index sürdürülebilir yükü taşımıyor

Her iki koşu da saniyede 2.000 iş hedefiyle başladı.

Strateji Başlangıç 900. saniye Kuyruk derinliği
partial 2.024 tps · 1,7 ms 2.016 tps · 4.906 ms 5.003 → 14.364
composite hedefi tutamadı 2.000 tps · 0,52 ms 1.204 tps · 61.533 ms 5.000 → 126.024
Gecikme pgbench'in zamanlama gecikmesini içeriyor: hedeflenen hıza yetişemeyen bir istemcinin borcu buraya yazılıyor.

Composite hedefi tutamadı — 2.000’den 1.204 tps’ye düştü, gecikmesi 61 saniyeye çıktı, kuyruğu 126 bine tırmandı. Partial hedefi tuttu.

Bu, otuz saniyelik ölçümün tersi yönde bir sonuç. Orada ikisi neredeyse eşitti (10.795 vs 11.537 tps). Fark sürdürülebilir yükte açılıyor, çünkü 427 megabayta şişmiş bir index artık belleğe sığmıyor ve her tarama diske gidiyor.

Cevaba dönüş

Sor Bakalım cevabının altı maddesinden beşincisi buydu ve tek sınanmayan oydu. Sonuç: madde doğru ama uyarısı zayıf. “Autovacuum’un sağlıklı çalışması önemli” cümlesi, varsayılan ayarlarla autovacuum’un bu tabloda sağlıklı çalışmadığını söylemiyor.

Partial index’i seçmenin bedeli iki kalemde: ölü index girdileri iş hacmiyle birikiyor, ve o birikimi temizleyecek mekanizma tablo bazında ayarlanmadıkça gelmiyor.

İlgili yazılar

Paylaş:

Diğer Kayıtlar

Tüm kayıtlar

Partial index kuyruk tablosunu kırk bir kat küçültüyor — planner onu seçtiği sürece

Milyonlarca ölü satır biriken bir Postgres kuyruk tablosunda partial index ne kazandırıyor, ve planner onu ne zaman seçmiyor?

Bulgu

10 milyon ölü satırda partial index saniyede 11.537 iş çıkarıyor, index'siz tablo 7. Composite index'le hız farkı küçük (%6,9) ama boyut farkı değil: 7,6 MB'a karşı 310,4 MB, ve partial tabloyla birlikte büyümüyor çünkü yalnız 5.000 canlı satırı indeksliyor. Asıl bulgu bunların hiçbiri: planner hazırlanmış bir deyimde generic plana geçtiği anda partial index tamamen devre dışı kalıyor — 11.752 tps 7'ye, 0,68 ms 1,1 saniyeye düşüyor. Bin altı yüz yetmiş üç kat. Aynı koşulda composite index etkilenmiyor.

dün ölçüldü

Yüksek güven

Postgres partial index'i generic plana çevirmedi: kırk çalıştırma, kırk custom plan

Hazırlanmış bir deyimde Postgres partial index'li sorguyu kendiliğinden generic plana çeviriyor mu — yoksa bin altı yüz yetmiş üç katlık uçuruma ancak elle mi düşülüyor?

Bulgu

Postgres geçişi reddediyor. Partial index'te kırk çalıştırmanın kırkı da custom plan — sayaç 40/0. Reddetmesinin sebebi tam olarak felaketin kendisi: generic plan partial index'i kullanamaz, bu yüzden tahmini maliyeti yüksek çıkar ve planner onu seçmez. Composite index ise ders kitabındaki gibi altıncı çalıştırmada geçiyor (5/35) ve hiçbir şey kaybetmiyor. Yani bin altı yüz yetmiş üç katlık uçurum gerçek ama çitli: ona düşmek için `plan_cache_mode = force_generic_plan` yazmak gerekiyor.

dün ölçüldü

Yüksek güven

Laravel'in preload eğrisi: 123 dosya, 1.912 dosyadan sekiz kat fazla kazandırıyor

Laravel için elle seçilmiş bir preload nereye kadar iner, ve her dilim ne kadar açılış bedeline mal olur?

Bulgu

Eğri hacimle orantılı değil. İlk 1.592 dosya (Laravel çekirdeği) 30 ms kazandırıyor ve açılışa 1,2 saniye ekliyor. Sonraki 1.094 Symfony dosyası 9,5 ms kazandırıyor, bedava. Ondan sonraki **123 dosya** (psr, carbon) 15,7 ms kazandırıyor — kendinden önceki 1.094 dosyadan fazla. Ve son 1.912 dosya yalnız 1,8 ms kazandırıp açılışa 1,2 saniye daha yazıyor. Yani önceki kaydın tavan olarak ölçtüğü "hepsini derle", eğrinin başlangıç noktası dışındaki en kötü fiyat/performans bölgesi: 2.809 dosyada durmak 12,77 ms ve 1.514 ms açılış verirken, 4.721 dosya 10,96 ms için 2.691 ms istiyor.

dün ölçüldü

Yüksek güven

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi