PostgreSQL'de UPDATE ve DELETE eski satır sürümünü hemen silmez; satır "ölü" olarak tabloda kalır. VACUUM bu ölü satırların kapladığı alanı yeniden kullanılabilir hâle getirir, planlayıcı istatistiklerini (ANALYZE ile) günceller, görünürlük haritasını işaretler ve transaction kimliği taşmasına (wraparound) karşı eski satırları dondurur. Autovacuum bu işleri arka planda kendiliğinden yapar; temizlik yetişemezse tablo gereksiz yere büyür, buna "bloat" (şişme) denir.
Bu yazıda bloat'ın nasıl oluştuğunu tablo boyutlarıyla gösteriyor, VACUUM, VACUUM FULL ve ANALYZE farkını, autovacuum'un ne zaman tetiklendiğini, uzun açık bir transaction'ın temizliği nasıl engellediğini ve wraparound uyarılarını anlatıyoruz. Genel bakım önerileri ve yapılandırma değerleri için PostgreSQL performans optimizasyonu yazısı kısa bir özet sunar; burada mekanizmanın ayrıntısına iniyoruz.
Neden VACUUM gerekir?

PostgreSQL'in çok sürümlü eşzamanlılık modelinde (MVCC) bir satır güncellendiğinde yeni bir sürüm yazılır, eskisi ise o satırı hâlâ görebilecek transaction'lar için bir süre saklanır. Bu mekanizma izolasyon seviyeleri yazısında xmin ve ctid sütunlarıyla gösteriliyor. Eski sürüm artık hiçbir transaction'ı ilgilendirmediğinde kapladığı alanın geri kazanılması gerekir. Kılavuz VACUUM'un dört görevini şöyle sıralar:
- Güncellenen veya silinen satırların kapladığı disk alanını geri kazanmak ya da yeniden kullanılabilir yapmak.
- Sorgu planlayıcısının kullandığı veri istatistiklerini güncellemek.
- Index-only taramaları hızlandıran görünürlük haritasını (visibility map) güncellemek.
- Transaction kimliği veya multixact kimliği taşması (wraparound) nedeniyle çok eski verinin kaybolmasını önlemek.
Bloat'ı gözle görmek
Autovacuum'u yalnızca bu tablo için kapatıp 100.000 satır ekledik, sonra her satırı bir kez güncelledik:
CREATE TABLE sepet (id int PRIMARY KEY, urun text, adet int) WITH (autovacuum_enabled = off);
INSERT INTO sepet SELECT i, 'ürün ' || i, 1 FROM generate_series(1, 100000) i;
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut;
UPDATE sepet SET adet = adet + 1;
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut;
SELECT n_live_tup, n_dead_tup, last_vacuum, last_autovacuum
FROM pg_stat_user_tables WHERE relname = 'sepet'; boyut
---------
5096 kB
(1 row)
UPDATE 100000
boyut
----------
10192 kB
(1 row)
n_live_tup | n_dead_tup | last_vacuum | last_autovacuum
------------+------------+-------------+-----------------
100000 | 100000 | |
(1 row)Tek bir UPDATE tablonun boyutunu ikiye katladı: 100.000 canlı satırın yanında 100.000 ölü sürüm duruyor. pg_stat_user_tables görünümündeki n_dead_tup sütunu bu sayıyı tahmini olarak gösterir. (İstatistikler biriktirilerek yayımlandığı için denemede sorgudan önce bir saniye bekledik.) Şimdi VERBOSE seçeneğiyle temizlik yapalım:
VACUUM (VERBOSE) sepet;INFO: vacuuming "ornek_vacuum.public.sepet"
INFO: finished vacuuming "ornek_vacuum.public.sepet": index scans: 1
pages: 0 removed, 1274 remain, 1274 scanned (100.00% of total), 0 eagerly scanned
tuples: 100000 removed, 100000 remain, 0 are dead but not yet removable
removable cutoff: 1016, which was 0 XIDs old when operation ended
new relfrozenxid: 1015, which is 2 XIDs ahead of previous value
frozen: 0 pages from table (0.00% of total) had 0 tuples frozen
visibility map: 1274 pages set all-visible, 636 pages set all-frozen (0 were all-visible)
index scan needed: 637 pages from table (50.00% of total) had 100000 dead item identifiers removed
index "sepet_pkey": pages: 551 in total, 0 newly deleted, 0 currently deleted, 0 reusable
avg read rate: 0.000 MB/s, avg write rate: 1.355 MB/s
buffer usage: 3760 hits, 0 reads, 4 dirtied
WAL usage: 3100 records, 4 full page images, 1077433 bytes, 0 buffers full
system usage: CPU: user: 0.00 s, system: 0.01 s, elapsed: 0.02 s
...
VACUUMÇıktının sonundaki TOAST tablosuna ait bölümü ... ile kısalttık. En önemli satır tuples: 100000 removed: bütün ölü sürümler temizlendi. index scan needed satırı indeksteki ölü kayıtların da silindiğini, visibility map satırı ise sayfaların "herkese görünür" olarak işaretlendiğini söylüyor. Peki tablo küçüldü mü?
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut; -- sonuç: 10192 kB
SELECT n_live_tup, n_dead_tup, vacuum_count FROM pg_stat_user_tables WHERE relname = 'sepet';
UPDATE sepet SET adet = adet + 1;
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut; -- sonuç: 10192 kB n_live_tup | n_dead_tup | vacuum_count
------------+------------+--------------
100000 | 0 | 1
(1 row)Boyut aynı kaldı. Kılavuzun anlattığı gibi standart VACUUM alanı işletim sistemine geri vermez, aynı tablo içinde yeniden kullanıma açar. İkinci UPDATE tabloyu büyütmedi, çünkü yeni sürümler boşalan yerlere yazıldı. Rutin vacuum'un amacı tabloyu en küçük boyutunda tutmak değil, iki temizlik arasında kullanılan alan kadar payla sabit bir boyutta tutmaktır.
VACUUM, VACUUM FULL ve ANALYZE farkı

Standart VACUUM, tablonun sonundaki sayfalar tamamen boşalmışsa ve kısa süreli özel bir kilit kolayca alınabiliyorsa bu sayfaları keserek dosyayı küçültebilir. VACUUM FULL ise tablonun tamamını boşluksuz yeni bir dosyaya yeniden yazar. Satırların %90'ını sildikten sonra ikisini karşılaştırdık:
DELETE FROM sepet WHERE id > 10000;
VACUUM sepet;
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut; -- sonuç: 5096 kB
VACUUM FULL sepet;
SELECT pg_size_pretty(pg_relation_size('sepet')) AS boyut; -- sonuç: 512 kBNormal VACUUM dosyanın sonundaki boş sayfaları kesip 10192 kB'tan 5096 kB'a indirdi; VACUUM FULL ise geri kalan boşlukları da atarak tabloyu 512 kB'a sıkıştırdı. Ancak bunun bedeli büyüktür:
| Komut | Ne yapar | Kilit | Ne zaman |
|---|---|---|---|
| VACUUM | Ölü satırları temizler, alanı tablo içinde yeniden kullanıma açar | SHARE UPDATE EXCLUSIVE: okuma ve yazma devam eder | Rutin bakım; autovacuum bunu yapar |
| VACUUM FULL | Tabloyu yeni dosyaya yazar, alanı işletim sistemine geri verir | ACCESS EXCLUSIVE: tabloya hiçbir erişim olmaz | Satırların çoğu silindiyse ve alan gerçekten gerekiyorsa |
| ANALYZE | Satır örneklemiyle planlayıcı istatistiklerini toplar | SHARE UPDATE EXCLUSIVE | Büyük veri değişikliklerinden sonra |
| VACUUM ANALYZE | Önce VACUUM, sonra ANALYZE | SHARE UPDATE EXCLUSIVE | Bakım betikleri için pratik birleşim |
Kılavuza göre VACUUM FULL çok daha yavaştır ve işlem bitene kadar tablonun yeni kopyası için ek disk alanı gerektirir. Bu yüzden yöneticilerin standart VACUUM kullanması ve VACUUM FULL'dan kaçınması önerilir; autovacuum da hiçbir zaman VACUUM FULL çalıştırmaz. Bir tablonun içeriği düzenli olarak tamamen siliniyorsa DELETE yerine TRUNCATE kullanmak ayrıca vacuum gerektirmez; kılavuz bunun katı MVCC anlamını bozduğunu da not eder. Kilit kiplerinin anlamı kilitler yazısında tablo hâlinde verildi.
VACUUM transaction bloğu içinde çalıştırılamaz, bir tabloyu temizlemek için o tablo üzerinde MAINTAIN yetkisi gerekir (veritabanı sahipleri paylaşılan kataloglar dışındaki tabloları temizleyebilir) ve yetkiniz olmayan tablolar sessizce atlanır. Tablo adı verilmezse geçerli veritabanındaki bütün tablolar işlenir. Diğer yararlı seçenekler şunlardır:
| Seçenek | Anlamı |
|---|---|
| FREEZE | Agresif dondurma; vacuum_freeze_min_age ve vacuum_freeze_table_age sıfırmış gibi çalışır |
| SKIP_LOCKED | Hemen kilitlenemeyen tabloyu beklemeden atlar |
| INDEX_CLEANUP | AUTO (varsayılan), ON veya OFF; indeks temizliğini zorlar ya da atlar |
| TRUNCATE | Sondaki boş sayfaları kesme denemesi; false yapılırsa bunun gerektirdiği ACCESS EXCLUSIVE kilidinden kaçınılır |
| PARALLEL n | İndeks temizliği aşamalarını paralel işçilerle yapar; FULL ile kullanılamaz |
| BUFFER_USAGE_LIMIT | VACUUM'un kullanacağı halka arabellek boyutu; 128 kB ile 16 GB arası |
Uzun açık transaction temizliği engeller
Bloat'ın en sinsi nedeni, vacuum'un çalışıyor görünmesine rağmen hiçbir şeyi temizleyememesidir. Bir satır sürümü, onu görebilecek en eski transaction bitene kadar silinemez. Aşağıda A oturumu bir REPEATABLE READ transaction'ını üç saniye açık tutarken B 5.000 satır silip hemen vacuum çalıştırıyor, sonra A bitince tekrar deniyor:
-- Oturum A
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT count(*) FROM sepet;
SELECT pg_sleep(3);
COMMIT;
-- Oturum B (yarım saniye sonra)
DELETE FROM sepet WHERE id <= 5000;
VACUUM (VERBOSE) sepet;
SELECT pid, state, backend_xmin, age(backend_xmin) AS xmin_yasi, left(query, 30) AS sorgu
FROM pg_stat_activity WHERE backend_xmin IS NOT NULL AND pid <> pg_backend_pid();
SELECT pg_sleep(3);
VACUUM (VERBOSE) sepet;-- Oturum B, birinci VACUUM (yalnızca tuples satırı)
tuples: 0 removed, 10000 remain, 5000 are dead but not yet removable
pid | state | backend_xmin | xmin_yasi | sorgu
-------+--------+--------------+-----------+---------------------
83636 | active | 1021 | 1 | SELECT pg_sleep(3);
(1 row)
-- Oturum B, A bittikten sonraki ikinci VACUUM (yalnızca tuples satırı)
tuples: 5000 removed, 5000 remain, 0 are dead but not yet removableBirinci denemede 5.000 ölü satır "dead but not yet removable" olarak kaldı, çünkü A'nın görüntüsü onları hâlâ görebiliyordu. pg_stat_activity görünümündeki backend_xmin sütunu, bu engeli koyan oturumu gösteriyor. A bitince ikinci vacuum bütün satırları temizledi. Gerçek sistemlerde bu A oturumu saatlerce "idle in transaction" kalmış bir uygulama bağlantısı, unutulmuş bir hazırlanmış transaction veya kullanılmayan bir replikasyon slotu olabilir. Kılavuz, idle_in_transaction_session_timeout parametresinin bu amaçla kullanılabileceğini belirtir; ayrıntılar transaction yazısında, uzun oturumları bulma yöntemleri ise pg_stat_activity yazısında.
Autovacuum ne zaman çalışır?
Autovacuum, bir başlatıcı (launcher) süreç ile onun başlattığı işçi (worker) süreçlerinden oluşur. Başlatıcı her veritabanında yaklaşık autovacuum_naptime aralığıyla bir işçi başlatmaya çalışır; aynı anda en fazla autovacuum_max_workers işçi çalışır. İşçiler istatistik sayaçlarına bakarak hangi tablonun temizlik veya analiz gerektirdiğine karar verir, bu yüzden track_counts açık olmalıdır. Kılavuzdaki formüle göre bir tablo, son vacuum'dan bu yana güncellenen veya silinen satır sayısı şu eşiği aştığında temizlenir:
vacuum eşiği = en küçük( autovacuum_vacuum_max_threshold,
autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor x reltuples )
analiz eşiği = autovacuum_analyze_threshold + autovacuum_analyze_scale_factor x reltuplesVarsayılan değerleri kendi test kümemizde pg_settings görünümünden okuduk:
SELECT name, setting, unit FROM pg_settings
WHERE name IN ('autovacuum', 'autovacuum_naptime', 'autovacuum_max_workers',
'autovacuum_vacuum_threshold', 'autovacuum_vacuum_scale_factor',
'autovacuum_vacuum_max_threshold', 'autovacuum_analyze_scale_factor',
'autovacuum_freeze_max_age')
ORDER BY name; name | setting | unit
---------------------------------+-----------+------
autovacuum | on |
autovacuum_analyze_scale_factor | 0.1 |
autovacuum_freeze_max_age | 200000000 |
autovacuum_max_workers | 3 |
autovacuum_naptime | 60 | s
autovacuum_vacuum_max_threshold | 100000000 |
autovacuum_vacuum_scale_factor | 0.2 |
autovacuum_vacuum_threshold | 50 |
(8 rows)Bu değerlerle 1.000.000 satırlık bir tablo, 50 + 0,2 x 1.000.000 = 200.050 ölü satırı geçince temizlenir. 1 milyar satırlık bir tabloda formül 200 milyonu verir; PostgreSQL 18 ile gelen autovacuum_vacuum_max_threshold (varsayılan 100 milyon) bu durumda üst sınır olarak devreye girer. Analiz için de benzer bir eşik vardır ve ekleme, güncelleme, silme toplamına bakar. Yalnızca ekleme alan tablolar için ayrıca autovacuum_vacuum_insert_threshold ve autovacuum_vacuum_insert_scale_factor ile tanımlanan bir ekleme eşiği bulunur.
Autovacuum'u iş başında görmek için kendi test kümemizde autovacuum_naptime değerini geçici olarak bir saniyeye indirdik, bir tabloya 1.000 satır ekleyip 600'ünü sildik ve bağlantıyı kapattık. Ayrı bir oturumda beş saniye sonra baktık:
ALTER SYSTEM SET autovacuum_naptime = '1s';
SELECT pg_reload_conf();
CREATE TABLE oturum_log (id int, veri text);
INSERT INTO oturum_log SELECT i, 'x' FROM generate_series(1, 1000) i;
DELETE FROM oturum_log WHERE id <= 600;
-- yeni oturumda, beş saniye sonra:
SELECT n_live_tup, n_dead_tup, last_autovacuum IS NOT NULL AS otomatik_calisti,
autovacuum_count, autoanalyze_count
FROM pg_stat_user_tables WHERE relname = 'oturum_log';
ALTER SYSTEM RESET autovacuum_naptime;
SELECT pg_reload_conf(); n_live_tup | n_dead_tup | otomatik_calisti | autovacuum_count | autoanalyze_count
------------+------------+------------------+------------------+-------------------
400 | 0 | t | 1 | 1
(1 row)Autovacuum hem temizliği hem analizi kendiliğinden yaptı. İlk denememizde silme ve kontrol aynı oturumdaydı ve sonuç görünmedi: oturumun istatistik sayaçları sunucunun ortak istatistiklerine o anda henüz aktarılmamıştı. Bu, izleme sorgularında karşılaşabileceğiniz bir gecikmedir. ALTER SYSTEM ve pg_reload_conf kullanımı yapılandırma yazısında ayrıntılı anlatılıyor.
Tablo bazında autovacuum ayarı
Genel eşikler bütün tablolara uyar ama çok sık güncellenen büyük bir tablo için yüzde 20 fazla gelebilir. Kılavuz, eşiklerin ve diğer pek çok autovacuum parametresinin tablo depolama parametreleriyle tek tek değiştirilebildiğini belirtir:
ALTER TABLE sepet SET (autovacuum_enabled = on, autovacuum_vacuum_scale_factor = 0.05);
SELECT relname, reloptions FROM pg_class WHERE relname = 'sepet'; relname | reloptions
---------+-------------------------------------------------------------
sepet | {autovacuum_enabled=on,autovacuum_vacuum_scale_factor=0.05}
(1 row)Kılavuz birkaç istisnayı da vurgular: autovacuum geçici tablolara erişemez, yabancı tablolarda ANALYZE çalıştırmaz ve bölümlenmiş (partitioned) üst tabloları işlemez; bölümlerin kendisini ise normal tablo gibi işler. Bölümlenmiş tablonun istatistikleri için zaman zaman elle ANALYZE çalıştırmanız gerekir; bu konu tablo bölümleme yazısında ele alınıyor. Ayrıca autovacuum işçileri genellikle diğer komutları bekletmez: çakışan bir kilit istendiğinde kendisi kesilir. Wraparound'u önlemek için çalışan bir autovacuum ise (pg_stat_activity'de sorgu adı (to prevent wraparound) ile biter) kendiliğinden kesilmez.
Transaction kimliği taşması (wraparound) ve dondurma
MVCC, transaction kimliklerini (XID) karşılaştırarak çalışır ve bu kimlikler 32 bitliktir. Kılavuzun açıklamasıyla, bir küme 4 milyardan fazla transaction çalıştırdığında sayaç başa döner ve geçmişteki transaction'lar birden "gelecekte" görünmeye başlar; bu, verinin görünmez olması demektir. Bunu önlemek için her tablonun her veritabanında en az iki milyar transaction'da bir vacuum görmesi gerekir. VACUUM yeterince eski satırları "donmuş" (frozen) olarak işaretler; donmuş satırlar her normal transaction'a göre geçmişte kabul edilir. Tabloların ve veritabanlarının yaşını kılavuzdaki sorgularla izleyebilirsiniz:
SELECT c.oid::regclass AS tablo, age(c.relfrozenxid) AS yas
FROM pg_class c WHERE c.relname = 'sepet';
SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY datname; tablo | yas
-------+-----
sepet | 1
(1 row)
datname | age
---------------+-----
ornek_explain | 276
ornek_izo | 276
ornek_kilit | 276
ornek_part | 276
ornek_tx | 276
ornek_vacuum | 276
postgres | 276
template0 | 276
template1 | 276
(9 rows)Yeni kurulmuş test kümemizde yaşlar çok küçük. autovacuum_freeze_max_age (varsayılan 200 milyon) değerini aşan tablolar için autovacuum, kapalı olsa bile, zorunlu olarak çalıştırılır. Bu da başarısız olursa sistem, wraparound noktasına kırk milyon transaction kaldığında aşağıdaki gibi uyarılar vermeye başlar ve üç milyon kaldığında yeni XID atamayı reddeder (kılavuzdaki örnek çıktılar):
WARNING: database "mydb" must be vacuumed within 39985967 transactions
HINT: To avoid XID assignment failures, execute a database-wide VACUUM in that database.
ERROR: database is not accepting commands that assign new transaction IDs to avoid wraparound data loss in database "mydb"
HINT: Execute a database-wide VACUUM in that database.Kılavuz bu durumda sunucuyu durdurmanın ya da tek kullanıcı kipine geçmenin gerekli olmadığını, şu adımların izlenmesini önerir: eski hazırlanmış transaction'ları (pg_prepared_xacts) commit veya geri almak, uzun süren açık transaction'ları (pg_stat_activity'de age(backend_xid) veya age(backend_xmin) büyük olanlar) sonlandırmak, eski replikasyon slotlarını kaldırmak ve hedef veritabanında VACUUM çalıştırmak. Bu senaryoda VACUUM FULL ve VACUUM FREEZE kullanılmamalıdır; ilki XID gerektirir, ikincisi gereğinden fazla iş yapar. Replikasyon slotları için streaming replication yazısına bakabilirsiniz.
PostgreSQL 18'de vacuum ile ilgili değişiklikler
PostgreSQL 18 sürüm notlarında bu konuya dokunan çok sayıda madde var:
- Normal vacuum, dondurma gerekmeden önce de bazı tamamen görünür sayfaları dondurabiliyor ("eager" tarama); bu, sonraki tam dondurma yükünü azaltır ve
vacuum_max_eager_freeze_failure_rateile ayarlanır. VERBOSE çıktısındakieagerly scannedsayısı bunu gösterir. - Dosya sonu kesmeyi kontrol eden
vacuum_truncatesunucu parametresi eklendi. - Autovacuum tetiklemesi için sabit üst sınır veren
autovacuum_vacuum_max_thresholdeklendi. autovacuum_worker_slotsile ayrılan yuvalar sayesindeautovacuum_max_workerssunucuyu yeniden başlatmadan bu sınıra kadar değiştirilebiliyor.pg_stat_all_tablesve türevlerinetotal_vacuum_time,total_autovacuum_time,total_analyze_timevetotal_autoanalyze_timesütunları eklendi.VACUUMveANALYZEartık kalıtım alt tablolarını da işliyor; eski davranış için yeniONLYseçeneği kullanılıyor. Bölümlenmiş tabloyu çocukları olmadan işlemek deONLYile mümkün.- VERBOSE çıktısına ve autovacuum günlüğüne WAL arabelleğinin dolduğu sayısı (
buffers full) eklendi; yukarıdaki çıktıda görebilirsiniz.
Bu sürümdeki diğer yenilikler için PostgreSQL 18 yenilikleri yazısına bakabilirsiniz.
Sık yapılan hatalar

- Disk dolunca VACUUM FULL'a koşmak: Tablonun yeni kopyası için ek alan gerekir ve tablo işlem boyunca tamamen kilitlenir.
- Autovacuum'u kapatmak: Kılavuz bunu son derece öngörülebilir iş yükleri dışında önermez; kapalıyken bile wraparound önleme çalışmaları yapılır.
- Uzun açık transaction'ları gözden kaçırmak: Vacuum çalışır ama hiçbir şey silemez; VERBOSE çıktısındaki "dead but not yet removable" sayısına bakın.
- Toplu yüklemeden sonra ANALYZE'ı unutmak: Autovacuum yetişene kadar planlayıcı eski istatistiklerle çalışır. Etkisini EXPLAIN yazısında gerçek planlarla gösterdik.
- Bölümlenmiş üst tabloyu analiz etmemek: Autovacuum üst tablonun istatistiğini toplamaz.
- Her veritabanını temizlemeyi unutmak: Elle vacuum yapıyorsanız kümedeki her veritabanı ayrı ayrı ele alınmalıdır; kılavuz bunun için
vacuumdbprogramını önerir. Zamanlama için crontab rehberine bakabilirsiniz.
Sık Sorulan Sorular
VACUUM tabloyu kilitler mi?
Standart VACUUM SHARE UPDATE EXCLUSIVE alır; SELECT, INSERT, UPDATE ve DELETE normal çalışmaya devam eder, yalnızca ALTER TABLE gibi şema değişiklikleri bekler. VACUUM FULL ise tabloya her türlü erişimi engeller.
VACUUM sonrası tablo neden küçülmedi?
Standart vacuum alanı tablo içinde yeniden kullanıma açar; yalnızca dosyanın sonundaki tamamen boş sayfaları kesebilir. Alanı işletim sistemine geri vermek için VACUUM FULL gibi tabloyu yeniden yazan bir komut gerekir.
Autovacuum çalışıyor mu, nasıl anlarım?
pg_stat_user_tables görünümündeki last_autovacuum, autovacuum_count, last_autoanalyze ve n_dead_tup sütunlarına bakın. Ayrıntılı günlük için log_autovacuum_min_duration parametresini kullanabilirsiniz; çalışan vacuum'ların ilerlemesi pg_stat_progress_vacuum görünümünde izlenir.
ANALYZE ne kadar sürer?
Kılavuz ANALYZE'ın bütün satırları okumadığını, rastgele bir örneklem kullandığını ve hızlı bir işlem olduğunu belirtir; bu yüzden pratikte genellikle bütün veritabanını analiz etmek önerilir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · PostgreSQL performans optimizasyonu · EXPLAIN ANALYZE ile plan okuma · MVCC ve izolasyon · pg_stat_activity ile izleme