Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

VACUUM vs VACUUM FULL - czym się różnią i kiedy który

W skrócie

  • Tabela puchnie mimo VACUUM, więc sięgasz po VACUUM FULL i nagle blokujesz całą tabelę na produkcji.
  • Zwykły VACUUM tylko zwalnia martwe wiersze do ponownego użycia w tabeli, a VACUUM FULL fizycznie przepisuje ją od nowa i oddaje miejsce systemowi.
  • Do codziennego utrzymania używaj zwykłego VACUUM (albo autovacuum), a VACUUM FULL trzymaj na wyjątkowe, jednorazowe odzyskanie miejsca w oknie serwisowym.

Nazwy sugerują, że VACUUM FULL to po prostu "mocniejszy VACUUM", i właśnie to nieporozumienie kosztuje ludzi zablokowaną produkcję. To są dwie zupełnie różne operacje o różnych skutkach i różnej cenie. Jedna działa w tle bez przeszkadzania, druga zatrzymuje dostęp do tabeli na czas przepisania jej od zera. Żeby dobrze utrzymywać bazę PostgreSQL, trzeba dokładnie rozumieć, co robi każda z nich i kiedy naprawdę potrzebujesz tej drugiej.

Jak to wygląda w praktyce

Widzisz, że tabela z częstymi aktualizacjami zajmuje na dysku znacznie więcej, niż wynikałoby z liczby aktualnych wierszy. Odpalasz zwykły VACUUM, a rozmiar na dysku wcale nie spada - i wyciągasz wniosek, że VACUUM nie działa. Sięgasz więc po VACUUM FULL na produkcyjnej tabeli w środku dnia i nagle wszystkie zapytania do niej stają w kolejce, aplikacja zwalnia albo się wywala, bo operacja trzyma wyłączną blokadę. Drugi wariant tego samego problemu: automatyczny autovacuum chodzi, ale tabela nadal jest rozdęta, bo trafiła na długo otwartą transakcję, która nie pozwala posprzątać martwych wierszy.

Dlaczego tak się dzieje

PostgreSQL działa na modelu wielowersyjnym. Aktualizacja wiersza nie nadpisuje go w miejscu - powstaje nowa wersja, a stara zostaje jako wiersz martwy, dopóki żadna transakcja może go jeszcze potrzebować. Zwykły VACUUM przechodzi po tabeli i oznacza przestrzeń po martwych wierszach jako wolną do ponownego użycia przez tę samą tabelę. To dlatego rozmiar na dysku po nim zwykle nie maleje: miejsce zostaje zarezerwowane w plikach tabeli i będzie zapełniane nowymi wierszami, zamiast wracać do systemu. VACUUM FULL robi coś zupełnie innego - przepisuje całą tabelę do nowego, ciasno upakowanego pliku i dopiero wtedy oddaje uwolnione miejsce systemowi operacyjnemu. Cena za to jest wysoka: na czas przepisywania bierze wyłączną blokadę, więc nikt nie poczyta ani nie zapisze tej tabeli, i chwilowo potrzebuje miejsca na dwie kopie danych naraz.

Jak to rozwiązać krok po kroku

  1. Do bieżącego utrzymania polegaj na autovacuum i ewentualnie ręcznym zwykłym VACUUM: VACUUM zamowienia;. To wystarcza, żeby tabela nie puchła w nieskończoność, bo odzyskane miejsce jest ponownie wykorzystywane.
  2. Jeśli chcesz przy okazji odświeżyć statystyki dla planera, połącz operacje: VACUUM ANALYZE zamowienia;. To dobry nawyk po dużych zmianach w danych.
  3. Zanim sięgniesz po VACUUM FULL, sprawdź, czy problemem nie jest długo otwarta transakcja, która blokuje sprzątanie. Zajrzyj do pg_stat_activity i zamknij zawieszone sesje z bardzo starym początkiem transakcji.
  4. VACUUM FULL uruchamiaj wyłącznie w oknie serwisowym i tylko dla konkretnej, mocno rozdętej tabeli: VACUUM FULL zamowienia;. Upewnij się wcześniej, że na dysku jest zapas miejsca na drugą kopię tabeli.
  5. Rozważ mniej blokującą alternatywę do odzyskania miejsca - rozszerzenie pg_repack przepisuje tabelę w tle bez wyłącznej blokady na cały czas operacji, co często jest lepsze na produkcji.
  6. Jeśli rozdęte są głównie indeksy, zamiast VACUUM FULL rozważ ich przebudowę - od PostgreSQL 12 dostępne jest REINDEX ... CONCURRENTLY, które przebudowuje indeks bez blokowania zapisów.

Jak sprawdzić, że zadziałało

Zmierz rozmiar tabeli przed i po. Przed operacją zanotuj pg_size_pretty(pg_total_relation_size('zamowienia')), wykonaj działanie i zapytaj ponownie. Po zwykłym VACUUM rozmiar na dysku zwykle się nie zmieni - to normalne, bo miejsce zostało zwolnione wewnętrznie; efekt potwierdzisz raczej spadkiem liczby martwych wierszy w widoku pg_stat_user_tables (kolumna n_dead_tup) oraz świeższą datą last_vacuum. Po VACUUM FULL rozmiar fizyczny powinien wyraźnie spaść. Warto też po większym sprzątaniu zerknąć, czy planer ma aktualne statystyki - kolumna last_analyze w tym samym widoku powie, kiedy ostatnio je odświeżono.

Wróć do listy: 100 najczęstszych pytań i problemów z PostgreSQL

Szkolenie Administracja, replikacja i tuning baz danych PostgreSQL

Sprawdź szkolenie: Administracja, replikacja i tuning baz danych PostgreSQL

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Szkolenie Zaawansowana administracja PostgreSQL - HA, DR, monitoring, skalowanie

Sprawdź szkolenie: Zaawansowana administracja PostgreSQL (HA, DR, monitoring, skalowanie)

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Czym naprawdę różni się VACUUM od VACUUM FULL?
Zwykły VACUUM oznacza miejsce po martwych wierszach jako wolne do ponownego użycia w tej samej tabeli i działa bez blokowania normalnej pracy. VACUUM FULL przepisuje całą tabelę do nowego, ciasnego pliku i oddaje uwolnione miejsce systemowi, ale bierze wyłączną blokadę, więc na jej czas tabela jest niedostępna.
Zrobiłem VACUUM, a rozmiar tabeli na dysku nie spadł - czy to błąd?
Nie, to normalne zachowanie. Zwykły VACUUM zwalnia przestrzeń wewnątrz plików tabeli do ponownego wykorzystania, a nie oddaje jej systemowi operacyjnemu. Dlatego rozmiar na dysku zwykle się nie zmienia. Fizyczne zmniejszenie pliku daje dopiero VACUUM FULL albo przepisanie tabeli innym narzędziem.
Kiedy naprawdę potrzebuję VACUUM FULL?
Rzadko - głównie do jednorazowego odzyskania dużej ilości miejsca po tabeli, która mocno spuchła, na przykład po masowym usunięciu danych. Uruchamiaj go w oknie serwisowym, bo blokuje tabelę, i miej zapas miejsca na dysku, bo chwilowo istnieją dwie kopie danych naraz. Do bieżącego utrzymania wystarcza zwykły VACUUM.
Czy jest sposób na odzyskanie miejsca bez blokowania tabeli?
Tak. Do przepisania tabeli w tle bez wyłącznej blokady na cały czas służy rozszerzenie pg_repack. Jeśli rozdęte są głównie indeksy, od PostgreSQL 12 możesz przebudować je poleceniem REINDEX ... CONCURRENTLY, które nie blokuje zapisów. Oba podejścia są bezpieczniejsze na produkcji niż VACUUM FULL.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...