PostgreSQL 13 – szczęśliwa liczba w świecie Postgresa

Wielu ludzi cierpi na irracjonalny lęk przed liczbą 13, co fachowo określa się mianem triskaidekafobii. W przypadku szykującego się najnowszego wydania PostgreSQL, opatrzonego właśnie tą liczbą, obawy są jednak bezzasadne. Niemal każdy będzie mógł w nim znaleźć zmiany poprawiające wykorzystywane na co dzień aspekty Postgresa.

Wielu ludzi cierpi na irracjonalny lęk przed liczbą 13, co fachowo określa się mianem triskaidekafobii. W przypadku najnowszego wydania PostgreSQL, opatrzonego właśnie tą liczbą, obawy są jednak bezzasadne. Niemal każdy znajdzie w nim zmiany poprawiające wykorzystywane na co dzień aspekty Postgresa.

Spróbujmy więc „odczarować” pozorną pechowość 13. wydania PostgreSQL. Pierwszą rzucającą się w oczy sprawą jest ogrom pracy włożony w to wydanie. Nie ma chyba podsystemów, na których polega wiele produkcyjnych wdrożeń, których to wydanie w jakiś sposób by nie dopieszczało.

Kilka ostatnich głównych wydań to duże zmiany w świecie PostgreSQL. Każde z nich przyniosło ogrom zmian i nowych funkcji jak na przykład partycjonowanie, natywna replikacja logiczna czy wsparcie dla typu JSON. W przypadku tego wydania sprawy mają się jednak inaczej i otrzymamy w nim poprawki dla już istniejących funkcji. Co nie znaczy, że nie mamy się czym ekscytować!

Mniejsze indeksy

Pierwszym ulepszeniem, które zdecydowanie przyda się wszystkim użytkownikom Postgresa, jest zmiana w wielkości standardowych indeksów opartych o B-drzewa (B-tree). Ten typ indeksu jest najczęściej wykorzystywany, ponieważ to właśnie on zostanie utworzony po wykonaniu polecenia CREATE INDEX. Zmniejszenie jego rozmiaru zdecydowanie cieszy, szczególnie że wraz z mniejszym rozmiarem można również spodziewać się szybszego dostępu do przechowywanych w nim informacji. Poprawka w wielkości indeksów głównie odnosi się do zmian w wykrywaniu zduplikowanych wartości (można o tym poczytać w dokumentacji implementacji B-drzew w Postgresie).

Jak to wygląda w praktyce? Korzystając z poniższego dość „zabawkowego” przykładu, możemy pokazać, jak zmiana pomiędzy głównymi wersjami może mieć wpływ na zajętość produkcyjnych dysków.

--- Przykładowa tablica
CREATE TABLE index_test(id int PRIMARY KEY, value int);
CREATE INDEX ON index_test (value);

--- Dodanie danych do tablicy
INSERT INTO index_test
    SELECT i, i % 12345
    FROM generate_series(1,1000000) i;

W przypadku wersji 12 wielkość indeksu, w którym znajdują się zduplikowane dane, prezentuje się następująco:

--- Wynik dla wersji 12
postgres=# select pg_size_pretty(pg_relation_size('index_test_pkey'));
 pg_size_pretty
----------------
 21 MB
(1 row)

Natomiast dla wersji 13 widzimy blisko 60%-ową redukcję rozmiaru:

postgres=# select pg_size_pretty(pg_relation_size('index_test_value_idx'));
 pg_size_pretty
----------------
 8664 kB
(1 row)

Jak wygląda porównanie wydajności? Od razu warto zaznaczyć, że tworzenie poprawnych testów tego typu to nietrywialne zadanie. Wydajność zależy od ogromnej ilości czynników, o niekoniecznie ortogonalnych czy nawet linearnych relacjach. Poniżej podajemy więc nasze wyniki, raczej jako anecdata niż twarde dane ;)

Skorzystaliśmy z poniższego zapytania:

EXPLAIN ANALYZE
SELECT count(*)
FROM index_test
WHERE value = 42;

Poniżej plan zapytania dla wersji 12:

                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=297.39..297.40 rows=1 width=8) (actual time=0.433..0.434 rows=1 loops=1)
   ->  Bitmap Heap Scan on index_test  (cost=5.05..297.19 rows=81 width=0) (actual time=0.118..0.394 rows=81 loops=1)
         Recheck Cond: (value = 42)
         Heap Blocks: exact=81
         ->  Bitmap Index Scan on index_test_value_idx  (cost=0.00..5.03 rows=81 width=0) (actual time=0.036..0.036 rows=81 loops=1)
               Index Cond: (value = 42)
 Planning Time: 0.490 ms
 Execution Time: 0.509 ms

Oraz dla wersji 13:

                                                                  QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------- ------
 Aggregate  (cost=6.04..6.05 rows=1 width=8) (actual time=0.059..0.060 rows=1 loops=1)
   ->  Index Only Scan using index_test_value_idx on index_test  (cost=0.42..5.84 rows=81 width=0) (actual time=0.046..0.052 rows=81 loops=1)
         Index Cond: (value = 42)
         Heap Fetches: 0
 Planning Time: 0.237 ms
 Execution Time: 0.082 ms

Jak widać, nawet tak podstawowe elementy bazy danych jak indeksy mogą wiele zyskać przy wprowadzeniu odpowiednich poprawek przez społeczność Open Source. W przypadku upgrade’u z poprzednich wersji, aby skorzystać z tej zmiany, trzeba będzie dokonać przebudowania indeksu. Na szczęście poprzednie 12 wydanie PostgreSQL dodało możliwość skorzystania z opcji REINDEX CONCURRENTLY. Nie trzeba więc przygotowywać okna serwisowego przez blokującą opcję REINDEX.

Nowe parametry ułatwiające monitorowanie

Monitorowanie działania bazy danych to jedna z podstawowych czynności administracyjnych. Jednym z nieprzebranych wręcz źródeł informacji są logi systemowe pozwalające na określenie stanu zdrowia bazy danych i wskazujące, gdzie kierować swoją uwagę w celu poprawienia jej wydajności. Jednym z narzędzi do analizy logów jest moduł  LogAnalyzer.

Aby najlepiej wykorzystać możliwości analizatora, należałoby zapisywać wszystkie zdarzenia w bazie danych. Nie jest to oczywiście możliwe w praktyce dla systemów produkcyjnych, ponieważ najwyższy poziom szczegółowości jest bardzo obciążający i powoduje obniżenie wydajności. Do czasu wersji 12 administratorzy mieli do wykorzystania parametr log_min_duration_statement powodujący zapisanie zapytania w logu, jeśli czas jego wykonania był dłuższy niż wartość graniczna. Pomagało to zidentyfikować pojedyncze długie zapytania. Jednak w dość oczywisty sposób powodowało skupianie się jedynie na wycinku rzeczywistości, nie dając poglądu na system bazodanowy jako całość.

W wersji 12 pojawił się parametr log_transaction_sample_rate, dzięki czemu można określić, jaki procent ze wszystkich zapytań zostanie zapisany w logu. Pozwala to na zmitygowanie problemu obniżenia wydajności, jednocześnie dając ogląd na stan całej bazy danych. PostgreSQL 13 rozwija ten pomysł i pozwala na dokładniejsze sterowanie logowaniem dzięki nowym parametrom konfiguracyjnym. Są to:

  • log_min_duration_sample – dodający możliwość logowania wolniejszych zapytań podobnie jak log_min_duration_statement
  • log_statement_sample_rate – kontrolujący próbkowanie dla powyższego parametru.

Dobranie odpowiednich wartości dla każdej aplikacji korzystającej z Postgresa mocno wykracza poza zakres tego artykułu. Warto jednak wspomnieć, że prawdopodobnie jedynie praktyczne testy pozwalają na znalezienia optymalnych ustawień.

Podsumowanie

Gratulujemy twórcom kolejnego dobrego kroku, a użytkowników zachęcamy do aktualizacji. PostgreSQL w wersji 13 został oficjalnie wydany w 24.09.2020 r. Szczegółowe informacje o wydaniu znajdziecie pod linkiem: https://www.postgresql.org/docs/13/release-13.html

blank Autorzy

Artykuły na blogu są pisane przez osoby z zespołu EuroLinux. 80% treści zawdzięczamy naszym developerom, pozostałą część przygotowuje dział sprzedaży lub marketingu. Dokładamy starań, żeby treści były jak najlepsze merytorycznie i językowo, ale nie jesteśmy nieomylni. Jeśli zauważysz coś wartego poprawienia lub wyjaśnienia, będziemy wdzięczni za wiadomość.