Yazılan/silinen satır sayısı arttıkça tablolar şişer (bloat), planner yanlış kararlar verir, disk dolar. autovacuum bunu temizlemek için var — ama varsayılan ayarları 2010'ların donanımına göre muhafazakâr. Yüksek yazma yükünde autovacuum sürekli geride kalır. İşte gerçekten fark yaratan dört parametre.
Önce kanıt: gerçekten geride mi?
Tahminle ayar değiştirme. Önce hangi tablonun ne kadar "ölü satır" biriktirdiğine bak:
SELECT
relname,
n_live_tup,
n_dead_tup,
round(100 * n_dead_tup /
greatest(n_live_tup, 1), 1) AS olu_yuzde,
last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
olu_yuzde yüksek ve last_autovacuum eskiyse ya da boşsa, autovacuum o tabloya yetişemiyor demektir.
1. autovacuum_vacuum_scale_factor
Varsayılan 0.2: tablonun %20'si ölü satıra dönmeden autovacuum tetiklenmez. 10 milyon satırlık tabloda bu 2 milyon ölü satır demektir — çok geç. Büyük ve sık güncellenen tablolarda bunu tablo bazında düşür:
ALTER TABLE siparisler
SET (autovacuum_vacuum_scale_factor = 0.02);
Artık %2'de tetiklenir. Küçük tablolar için global varsayılanı bozmaya gerek yok; sorunlu tabloyu hedefle.
2. autovacuum_vacuum_cost_limit
autovacuum kasıtlı olarak yavaştır — üretimi boğmasın diye her "maliyet" biriminden sonra uyur. Varsayılan 200 çoğu modern NVMe disk için fazla ihtiyatlı. Yükselttiğinde autovacuum daha hızlı çalışır:
# postgresql.conf
autovacuum_vacuum_cost_limit = 2000
Bu değeri agresif artırmak autovacuum'a I/O ve CPU verir — canlı trafikte diski doyurabilir. Prod'da kademeli çık (200 → 1000 → 2000) ve her adımda disk latency'sini izle. "Ne kadar çok o kadar iyi" değil; darboğazı taşımaktan ibaret.
3. autovacuum_max_workers
Aynı anda kaç tablo temizlenebilir. Varsayılan 3; onlarca sıcak tablon varsa worker'lar kuyruğa girer ve bekler:
autovacuum_max_workers = 6
Ama dikkat: autovacuum_vacuum_cost_limit tüm worker'lar arasında paylaşılır. Worker sayısını iki katına çıkarıp cost_limit'i sabit tutarsan, her worker yarı hızda çalışır. İkisini birlikte düşün.
4. autovacuum_naptime
autovacuum launcher'ın "yeni iş var mı" diye baktığı aralık. Varsayılan 1min. Çok sayıda hızlı değişen küçük tablo varsa (kuyruk tabloları gibi) düşürmek gecikmeyi azaltır:
autovacuum_naptime = 15s
Bonus: transaction ID wraparound
En tehlikeli senaryo bloat değil, wraparound. autovacuum sürekli geride kalırsa PostgreSQL kendini korumak için tabloyu okuma-yazmaya kapatabilir. Kalan payı izle:
SELECT
relname,
age(relfrozenxid) AS xid_yasi
FROM pg_class c
JOIN pg_stat_user_tables t ON t.relid = c.oid
ORDER BY age(relfrozenxid) DESC
LIMIT 10;
xid_yasi autovacuum_freeze_max_age (varsayılan 200M) değerine yaklaşıyorsa acil müdahale gerekir.
Özet
Global varsayılanları topluca değiştirmek yerine, pg_stat_user_tables'tan sorunlu tabloyu bul, scale_factor'ı o tabloda düşür, cost_limit'i kademeli yükselt ve worker/naptime dengesini yükün şekline göre kur. autovacuum'u "kapatmak" ise asla çözüm değil — sadece sorunu ertelemektir.