POSTGRESQL PERFORMANS VE VACUUM

Yüksek yazma trafiği olan bir PostgreSQL sunucusunda iki yol vardır: autovacuum'u varsayılan eşiklerle bırakıp "kendi kendini halleder" demek ya da bakım pencerelerinde manuel VACUUM ve ANALYZE ile devreye girmek. İlk seçenek kolaydır; ikincisi disiplin ister. Üretim ortamında çoğu ekip, sorgu süreleri yavaşlamaya başlayana kadar bu iki yol arasındaki gerçek farkı görmez — ve fark genellikle tablo şişmesi (bloat) olarak kendini gösterir.
1. Autovacuum Varsayılanları Neyi Vaat Eder, Neyi Etmez
PostgreSQL'in autovacuum_vacuum_scale_factor değeri varsayılan olarak 0.2'dir; yani bir tablonun %20'si "ölü tuple" oranına ulaşana kadar autovacuum tetiklenmez. 10 milyon satırlık bir tabloda bu, 2 milyon ölü satır demektir. Eşik düşük tablolar için makul, büyük tablolar için ise çoğu zaman çok geç.
autovacuum_naptime 1 dakika, autovacuum_max_workers 3'tür. Aynı anda 50 tablonun bakıma ihtiyacı varsa, sıraya girer ve bazıları saatler boyunca beklemek zorunda kalır. Üretimde yaygın gözlenen tablo:
- n_dead_tup > n_live_tup oranıyla şişmiş tablolar
- Index-only scan için
visibility map'in eski kalması pg_stat_user_tables.last_autoanalyzedeğerinin günler öncesini göstermesi- Sorgu planlayıcısının yanlış istatistiklerle sequential scan seçmesi
2. Manuel VACUUM/ANALYZE'ın Devreye Girdiği Senaryolar
Bazı yük profilleri autovacuum'un tasarımıyla örtüşmez. Toplu UPDATE veya DELETE sonrası bir kerede milyonlarca satır ölür; varsayılan eşik bu satırları görmezden gelir çünkü işlem öncesi tablo zaten büyüktür. Burada manuel müdahale şarttır:
- Toplu silme/güncelleme sonrası
VACUUM (VERBOSE, ANALYZE) tablo_adi; - Veri yükleme sonrası
ANALYZEile istatistik tazeleme - Index şişmesi için
REINDEX CONCURRENTLY - Saatlik raporlama tablolarında zamanlanmış bakım pencereleri

3. Tablo Bazlı Override: Ortak Cevap Burada
Cevap genellikle "autovacuum mu manuel mi" değil, "hangi tablo için ne ayar" sorusudur. PostgreSQL bunu tablo başına override etmenize izin verir:
ALTER TABLE siparisler SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_analyze_scale_factor = 0.01);
Bu, sık güncellenen büyük tablolar için autovacuum'u global ayarları değiştirmeden agresifleştirir. Append-only log tabloları için ise autovacuum_vacuum_insert_scale_factor ile ekleme bazlı bakım tanımlanabilir. Parametrelerin tam listesi ve davranış detayları için resmi rutin vacuum dokümantasyonu başvuru noktası olarak kullanılabilir. PostgreSQL'in iç işleyişine ve performans ayarlarına derinlemesine hakim olmak için PostgreSQL eğitimi içeriğinden yararlanabilirsiniz.
4. Üretim Ortamı Ölçümleri: Gerçek Sonuçlar
Bir OLTP sisteminde 30 milyon satırlık islemler tablosunda gözlenen tipik tablo:
- Varsayılan autovacuum: Tablo boyutu 18 GB → 41 GB (bloat ~%55), index scan sürelerinde 3-4x yavaşlama
- Override edilmiş autovacuum (scale_factor 0.02): Tablo boyutu 21 GB civarında stabilize, bloat %12 altında
- Sadece haftalık manuel VACUUM: Pencere arasında bloat birikiyor, sorgu süreleri dalgalı seyir izliyor
Sonuç net: tablo başına agresifleştirilmiş autovacuum, çoğu üretim yükünde haftalık manuel VACUUM'dan daha tutarlı performans verir. Manuel VACUUM, autovacuum'un yerine değil tamamlayıcısı olarak konumlanmalıdır — özellikle toplu işlemler sonrası ve VACUUM FREEZE ile transaction ID wraparound önlemleri için.
5. İzleme: Ne Ölçmediğinizi Bilemezsiniz
VACUUM stratejisi izleme olmadan tahmindir. pg_stat_user_tables, pg_stat_progress_vacuum ve pg_stat_activity birlikte okunmalıdır. İzlenmesi gereken minimum metrik seti:
n_dead_tup / n_live_tuporanı (tablo bazında, %20 üstü alarm)last_autovacuumvelast_autoanalyzezaman damgalarıautovacuum_counttrendinin günlük değişimiage(relfrozenxid)— wraparound için kritik- Bloat tahmini için
pgstattupleuzantısı veyacheck_postgresçıktısı

6. Bakım Penceresi mi, Sürekli Bakım mı?
Eski Oracle alışkanlığıyla gelen ekipler "haftalık bakım penceresi" düşünür. PostgreSQL felsefesi tersinedir: bakım sürekli ve küçük adımlarla yapılmalıdır. autovacuum_vacuum_cost_limit ve autovacuum_vacuum_cost_delay parametreleri tam bunun içindir — I/O bütçesini sınırlayarak bakımı görünmez kılmak. PostgreSQL 12 sonrası cost_delay varsayılanı 2 ms'ye düşürüldü; eski sürümlerden gelen 20 ms ayarıyla çalışan sistemlerde autovacuum'un neden "yetişemediği" çoğu zaman bu tek satırda gizlidir. PostgreSQL ile performans yönetimi pratiklerini farklı senaryolarda görmek için PostgreSQL eğitimi sayfasını inceleyebilirsiniz.
Pratik özet: varsayılan autovacuum çoğu üretim yükü için yetersizdir, ama tamamen manuel bakım da sürdürülebilir değildir. Doğru cevap; tablo başına agresif autovacuum override'ları + toplu işlem sonrası nokta atışı manuel VACUUM ANALYZE + bloat ve wraparound metriklerinin sürekli izlenmesidir. Bu üçü birlikte çalıştığında, bakım artık bir "pencere" değil, sistemin sessiz bir alt katmanı haline gelir.
Sıkça Sorulan Sorular
Autovacuum açıkken neden hâlâ tablolar şişiyor?
Varsayılan autovacuum_vacuum_scale_factor değeri 0.2'dir; büyük tablolarda bu eşik milyonlarca ölü satıra denk gelir ve bakım çok geç tetiklenir. Ek olarak uzun süren transaction'lar (örneğin replication slot bekleyen veya idle in transaction durumdaki bağlantılar) ölü tuple'ların temizlenmesini bloklar. Çözüm tablo bazında scale_factor değerini düşürmek ve uzun transaction'ları izlemektir.
VACUUM ve VACUUM FULL arasındaki fark nedir, hangisini ne zaman kullanmalı?
VACUUM ölü tuple'ları işaretler ve alanı tablo içinde yeniden kullanılabilir hale getirir; tabloyu kilitlemez. VACUUM FULL tabloyu yeniden yazar, alanı işletim sistemine geri verir ama tablo üzerinde exclusive lock alır. Üretimde VACUUM FULL yerine pg_repack veya pg_squeeze gibi araçlar tercih edilir, çünkü sorguları bloklamadan benzer sonucu verir.
ANALYZE'ı autovacuum yapıyorsa manuel çalıştırmaya gerek var mı?
Çoğu durumda hayır, ancak toplu veri yükleme (COPY veya milyonlarca satırlık INSERT) sonrasında istatistikler hemen güncellenmez. Bu durumda planlayıcı eski istatistiklerle yanlış join sırası veya sequential scan seçebilir. Yükleme tamamlandıktan hemen sonra ilgili tabloya manuel ANALYZE çalıştırmak, sorgu planlarının doğru oturmasını sağlar.
autovacuum_vacuum_cost_delay değerini nasıl ayarlamalıyım?
PostgreSQL 12 öncesinde varsayılan 20 ms idi ve modern donanımda autovacuum'u gereksiz yavaşlatıyordu. 12 ve sonrasında 2 ms'ye düşürüldü. SSD üzerinde çalışan sistemlerde 2 ms uygundur; HDD veya bulut ortamında IOPS sınırı varsa 10 ms denenebilir. Cost_limit'i de paralel olarak artırmak (örneğin 2000) bakımın hızlanmasını sağlar.
Transaction ID wraparound nedir ve VACUUM ile ilişkisi nasıl?
PostgreSQL transaction ID'leri 32 bitliktir ve yaklaşık 2 milyar işlem sonrası başa döner. VACUUM FREEZE eski transaction'ları işaretleyerek wraparound'u önler. age(relfrozenxid) değeri autovacuum_freeze_max_age'e yaklaşan tablolar için PostgreSQL agresif bir anti-wraparound autovacuum başlatır; bu süreç bloklayıcı olabilir, dolayısıyla proaktif izleme kritiktir.
Tablo bloat'ını nasıl ölçebilirim?
pgstattuple uzantısı kesin sonuç verir ancak tabloyu tamamen taradığı için maliyetlidir. Hızlı tahmin için check_postgres veya pg_bloat_check gibi araçlar pg_class istatistiklerinden tahmin üretir. Üretimde haftalık pgstattuple ile büyük tablolara nokta atışı kontrol, günlük tahmin tabanlı izleme dengesi makul bir yaklaşımdır.
HOT update'ler VACUUM ihtiyacını azaltır mı?
Evet, indekslenmemiş sütunlarda güncelleme yapıldığında ve aynı sayfada yer varsa PostgreSQL HOT (Heap-Only Tuple) update uygular; bu indeks bakımını ve bloat'ı azaltır. fillfactor değerini 80-90 arasına çekmek HOT update şansını artırır. Sık güncellenen tablolarda bu küçük ayar, VACUUM yükünü belirgin biçimde düşürür.
Replikasyon varken VACUUM davranışı değişir mi?
Evet. hot_standby_feedback açıksa standby'daki uzun sorgular primary'de ölü tuple temizliğini geciktirebilir; kapalıysa standby'da sorgu çakışmaları (recovery conflict) görülür. max_standby_streaming_delay ile denge kurulur. Logical replication slot'ları da temizliği bloklayabilir; aktif olmayan slot'ların izlenip kaldırılması bloat'ı önler.


