HomeAbout
 
  

Postgresql'de Vacuum ile Optimizasyon - Vacuum Nedir, Nasıl Çalışır?

September 1, 2022

Postgresql’de herhangi bir kayıt silindiğinde veya güncellendiğinde ardında silinmiş gibi görünen ancak yer kaplayan ölü alanlar bırakır. Vacuum, “dead-tuple” diye nitelendirilen bu ölü alanları kurtarmak için kullanılmaktadır. Vacuum işleminin ana görevi bu “dead-tuple”’ları yeniden kullanılabilir, üzerine yazılabilir hale getirmektir.

Update işleminin aslında INSERT ve DELETE işlemlerinin bir bütünü olduğunu hatırlayarak başlayalım. Güncelleme işleminde insert işlemi gerçekleştirilir ve eski satır silinir. Postgresql’de DELETE işlemi yürütüldüğünde bir satır fiziksel olarak siliniyormuş gibi yapılır. Bundan kasıt fiziksel olarak silinmez, diskte yer kaplar ancak silinmiş olarak işaretlenir ve gizlenir. Aynı durum DELETE işlemini barındırdığı için Update işlemi içinde geçerlidir.

Ölü alanlar, dead-tuple olarak işaretlenerek sorgularda okunmamaları ve işleme alınmamaları sağlanmaktadır. Bu ölü alanların temizlenmemesi disk alanında daha fazla yer kullanımına, yani “bloat” (şişme) oluşumuna neden olacaktır. Diskte tutulan bu ölü alanlar henüz kullanılmamışsa buradaki veriler çok çok düşük bir ihtimalle de olsa kurtarılabilir.

  • Dead-tuple’lar performansı olumsuz yönde etkileyebilir.
  • Disk üzerinde kayıt tutma boyutlarını artırır.
  • Yedek boyutlarını artırır.

Tüm bu dertler için çözümlerden en önemlisi Vacuum’dur. Vacuum, bloat’ları bizim robot süpürgemiz “Katya” misali temizlemekle yükümlüdür. Vacuum işlemi tüm page’leri tarar ve dead-tuple’ları freespacemap (FSM)’e işaretler.

İlk işimden sonra yaklaşık dört yıl önce bir mülakata girmiştim. Mülakatta cevap veremediğim tek soru vardı.

  • “Postgresql’de DB şiştiğinde ne gibi bir çözüm uygulanabilir?”
  • Cevap: “Vacuum” olmalıydı.

Vacuum işlemi tabloda tam olarak yer kazandırmamakta, ölü alanları yeniden yazılabilir hale getirmektedir. Böylece ölü alanlar azaltılarak kullanıma sunulabilir.

Vacuum işlemi bi nevi Postgresql’in Garbage Collector’ıdır.

Vacuum komutlarına kısaca değinip hemen detaylarına geçelim. Eğer belirli bir tablo üzerinde Vacuum işlemi gerçekleştiriyorsak Vacuum anahtar kelimesi ile birlikte tablo adını yazmamız yeterli olur.

VACUUM tablo_adı;

Bir diğer opsiyonumuz ise ANALYZE ifadesiyle birlikte Vacuum’u çalıştırmaktır. Analyze ile birlikte tabloda oluşmuş olabilecek istatistik bozulmaları ya da planner’ın daha verimli çalışmasını sağlayabiliriz. Analyze tablodaki veri istatistiklerini de güncelleyerek daha performanslı sorgular oluşturmanıza yardımcı olabilir.

VACUUM ANALYZE tablo_adı;

Vacuum’un çalışmasındaki detayları da görmek için VERBOSE ifadesiyle birlikte Vacuum çalıştırılabilir.

VACUUM VERBOSE tablo_adı;

Vacuum Nasıl Çalışır?

Vacuum dead-tuple’ları bulup, onları yeniden yazılabilir hale getirir. Peki bunu nasıl yapıyor?

  • Tüm ölü alanları bilmek için ilgili tablo/tabloları için tüm page'leri tarar.
  • ilk olarak bulunan dead-tuplelar silinir. (Yeniden kullanılabilir hale getirilir.)
  • Silinen Dead-Tuple’lar ile ilgili index satırları silinir. Vacuum yarıda kalırsa index bakımı yapılmalı, Reindex gerekiyorsa çalıştırılmalıdır.
  • Visibility map ve free_space_map güncellenir.
  • Son sürüm ile birlikte dead-tuple’ların sonları boş ise son satır sonrasını siler ve boş alan yaratmaya imkan sağlamış olur.
  • Vacuum bilgilerini/istatistiklerini de günceller.
  • İlgili tüm istatistik ve tablolar güncellenerek işlem tamamlanır.

AUTO VACUUM

PostgreSQL, otomatik olarak VACUUM’u tetikleyen bir mekanizmaya sahiptir. Auto-Vacuum ön tanımlı olarak aktiftir ve bir dakikaya ayarlıdır.

  • Kendinden daha fazla lock gereksinimi olan bir işlem gelirse vacuum işlemini tamamlamadan bitirir.
  • postgresql.conf dosyası üzerinden threshold, nap_time gibi birçok ayarı düzenlenebilir.
  • Tablo bazlı tanımlanabilir.

Auto-vacuum’un yanı sıra normal vacuum ya da cron bazlı vacuum önerilir. Auto vacuum çok işe yarardır ve kapatılması önerilmez.

ALTER TABLE gokhanadev SET(autovacuum_enabled = true);

Auto-Vacuum çalıştığı halde temizlik yapılmamış olabilir. Loglardan nedenleri incelenerek çözüme ulaşılabilir. Bir transaction işlemi bekletiyor olabilir.

ALTER TABLE gokhanadev SET (autovacuum_vacuum_scale_factor = 0.3,
autovacuum_vacuum_threshold = 20,
autovacuum_analyze_scale_factor = 0.2,
autovacuum_analyze_threshold = 20);

VACUUM FULL

Vacuum full işlemi ile birlikte ilgili tablonun tamamı kopyalanarak, yeniden yazılır. Tablo yeniden yazılırken dead-tuple’lardan arındırılır ve daha düzenli bir şekilde yazma işlemi gerçekleştirilir, böylece verinin kapladığı alan küçültülmüş olur.

Vacuum full kullanılırsa hem kullanılan tablo hem de ona bağlı tablolar üzerinde locklama işlemi gerçekleştirilir, VACUUM FULL sırasında ilgili tabloda işlem yapılamaz. Bu nedenle production’da kullanılması çok önerilmez ya da çok dikkatli olunmalıdır.

Vacuum Full için en az o tablo kadar boş alanınızın olması gerekmektedir, yeniden oluşturma işlemi için bu gereklidir. Çünkü Vacuum Full ile birlikte tablonun yeni bir kopyası oluşturulur.

VACUUM (FULL) tablo_adi;
  • İşlem yapılan tablo ve ona bağlı tablolar için exclusive lock atılır.
  • Yeniden kopyalama için boş bir alan oluşturulur.
  • Tüm tuple’lar/veriler bu yeni alana kopyalanır.
  • Kopyalama tamamlanınca, eski kalan alan temizlenir.
  • Ve son olarak atılan lock kaldırılır.

Vacuum Full kullanılırken dikkatli olunması gerekir, Devrim Gündüz Vacuum Full yerine PG_REPACK’i önermektedir. Pg_repack, concurrently olarak çalıştığı için bloklama yapmadan çok çok kısa kesinti ile işlemlerini tamamlar.


VACUUM’u Daha İyi Anlamak

Postgresql’de bir yazma işlemi sonucu veriler disk üzerinde 8 KB’lık page adı verilen bloklar halinde tutulur. İlk yazma işleminde page içindeki tüm satırlar görünebilirdir (visibility) ve true işaretlenir. Görünebilir dediğimiz şey aslında içerisinde ölü alan barındırmamasıdır ve yeniden kullanılabilir olmasıdır. En az bir tane satır bile görünmez ise o page false olarak işaretlenmektedir. False olarak işaretlenen herhangi bir satır üzerinden yeniden yazma işlemi gerçekleştirilemez. Bir page içerisinde en az bir tane bile satır Update olsa visibility’sini kaybetmiş demektir. pg_visibility adlı bir extension ile bu map detaylı incelenebilir. Page sayısı ve visiblity gözlemlenebilir.

CREATE EXTENSION pg_visibility;

Bir örnek üzerinden gidelim. Github repomda tüm adımlara erişebilirsiniz.

CREATE TABLE gokhanadev(id int, id2 int);

Bu tablo içerisine örneğimizi genişletmek için bir milyon adet veri üretelim. generate_series bize bu konuda yardımcı olacaktır.

INSERT INTO gokhanadev VALUES(generate_series(1,1000000), generate_series(1,1000000));

Şimdi pg_visibility ile birlikte bahsettiğimiz page bloklarının karşılığını görelim.

select count(blkno), all_visible from pg_visibility_map(‘gokhanadev’) group by all_visible;
count | all_visible
— — — -+ — — — — — — -
4425 | t
(1 row)

Şimdi dead-tuple’lar oluşturmak için bir Update işlemi gerçekleştirip, visibility_map’e bakıp ve dead-tuple’ların oluştuğu page sayısını gözlemleyebiliriz.

UPDATE gokhanadev set id = id + 1 where id > 50000;
UPDATE 950000
select count(blkno), all_visible from pg_visibility_map(‘gokhanadev’) group by all_visible;
count | all_visible
— — — -+ — — — — — — -
8408 | f
221 | t
(2 rows)

Ve artık Vacuum işlemini çalıştırabilir ya da bir dakika civarında Auto-Vacuum’un çalışmasını bekleyebiliriz.

VACUUM gokhanadev;
select count(blkno), all_visible from pg_visibility_map(‘gokhanadev’) group by all_visible;
count | all_visible
— — — -+ — — — — — — -
8629 | t
(1 row)

Dead-tupleların temizlenip, yeniden kullanılabilir hale geldiğini görebilirsiniz.


— Bana ulaşmak için: Twitter, Linkedin, Medium

— Kodlar konuşsun: Github

— 1:1 görüşmeler için: Superpeer

Kaynakça

 

Gökhan Ayrancıoğlu

Gökhan Ayrancıoğlu

Sr. Software Engineer @Heycar | Tech Blogger

 

Copyright © 2023 All rights reserved

Made with Coffee ☕