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:

sql
PG 17
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:

sql
PG 17
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:

ini
PG 17
# postgresql.conf
autovacuum_vacuum_cost_limit = 2000
Dikkat

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:

ini
PG 17
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:

ini
PG 17
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:

sql
PG 17
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.