PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Moje ulubione rozszerzenia PostgreSQL — część druga

To jest druga część mojego bloga „Moje ulubione rozszerzenia PostgreSQL”, w którym przedstawiłem Ci dwa rozszerzenia PostgreSQL, postgres_fdw i pg_partman. W tej części omówię jeszcze trzy.

pgAudit

Następne rozszerzenie zainteresowania PostgreSQL ma na celu spełnienie wymagań audytowych różnych organów rządowych, finansowych i innych instytucji certyfikujących, takich jak ISO, BSI i FISCAM, itp. Standardowa funkcja logowania, którą PostgreSQL oferuje natywnie z log_statement =all jest przydatne do monitorowania, ale nie zawiera szczegółów wymaganych do spełnienia lub zmierzenia się z audytem. Rozszerzenie pgAudit skupia się na szczegółach tego, co wydarzyło się pod maską, podczas gdy baza danych spełniała żądanie aplikacji.

Ścieżka audytu lub dziennik audytu jest tworzony i aktualizowany przez standardowe narzędzie rejestrowania dostarczane przez PostgreSQL, które zapewnia szczegółowe rejestrowanie audytu sesji i/lub obiektu. Ścieżka audytu stworzona przez pgAudit może mieć ogromny rozmiar w zależności od ustawień audytu, dlatego należy zachować ostrożność, aby zawczasu zdecydować, co i ile audytu jest wymagane. Krótkie demo w poniższej sekcji pokazuje, jak pgAudit jest skonfigurowany i używany.

Ślad dziennika jest tworzony w dzienniku klastra bazy danych PostgreSQL znalezionym w lokalizacji PGDATA/log, ale komunikaty dziennika audytu są poprzedzone etykietą „AUDIT:” w celu rozróżnienia między zwykłymi komunikatami w tle bazy danych a dziennikiem audytu dokumentacja.

Demo

Oficjalna dokumentacja pgAudit wyjaśnia, że ​​istnieje oddzielna wersja pgAudit dla każdej głównej wersji PostgreSQL w celu obsługi nowych funkcji wprowadzanych w każdym wydaniu PostgreSQL. Wersja PostgreSQL w tym demo to 11, więc wersja pgAudit będzie pochodzić z gałęzi 1.3.X. pgaudit.log jest podstawowym parametrem do ustawienia, który kontroluje, jakie klasy instrukcji będą rejestrowane. Można go ustawić za pomocą SET dla poziomu sesji lub w pliku postgresql.conf, aby zastosować go globalnie.

postgres=# set pgaudit.log = 'read, write, role, ddl, misc';

SET



cat $PGDATA/pgaudit.log

pgaudit.log = 'read, write, role, ddl, misc'



db_replica=# show pgaudit.log;

         pgaudit.log

------------------------------

 read, write, role, ddl, misc

(1 row)



2020-01-29 22:51:49.289 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,3,1,MISC,SHOW,,,show pgaudit.log;,<not logged>



db_replica=# create table t1 (f1 integer, f2 varchar);

CREATE TABLE



2020-01-29 22:52:08.327 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,4,1,DDL,CREATE TABLE,,,"create table t1 (f1 integer, f2 varchar);",<not logged>



db_replica=#  insert into t1 values (1,'one');

INSERT 0 1

db_replica=#  insert into t1 values (2,'two');

INSERT 0 1

db_replica=#  insert into t1 values (3,'three');

INSERT 0 1

2020-01-29 22:52:19.261 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,5,1,WRITE,INSERT,,,"insert into t1 values (1,'one');",<not logged>

20-01-29 22:52:38.145 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,6,1,WRITE,INSERT,,,"insert into t1 values (2,'two');",<not logged>

2020-01-29 22:52:44.988 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,7,1,WRITE,INSERT,,,"insert into t1 values (3,'three');",<not logged>



db_replica=# select * from t1 where f1 >= 2;

 f1 |  f2

----+-------

  2 | two

  3 | three

(2 rows)



2020-01-29 22:53:09.161 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,9,1,READ,SELECT,,,select * from t1 where f1 >= 2;,<not logged>



db_replica=# grant select on t1 to usr_replica;

GRANT



2020-01-29 22:54:25.283 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,13,1,ROLE,GRANT,,,grant select on t1 to usr_replica;,<not logged>



db_replica=# alter table t1 add f3 date;

ALTER TABLE



2020-01-29 22:55:17.440 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,23,1,DDL,ALTER TABLE,,,alter table t1 add f3 date;,<not logged>



db_replica=# checkpoint;

CHECKPOINT



2020-01-29 22:55:50.349 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,33,1,MISC,CHECKPOINT,,,checkpoint;,<not logged>



db_replica=# vacuum t1;

VACUUM



2020-01-29 22:56:03.007 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,34,1,MISC,VACUUM,,,vacuum t1;,<not logged>



db_replica=# show log_statement;

 log_statement

---------------

 none



2020-01-29 22:56:14.740 AEDT 4710 db_replica postgres [local] psql LOG:  AUDIT: SESSION,36,1,MISC,SHOW,,,show log_statement;,<not logged>

Wpisy dziennika, jak pokazano w powyższym demo, są zapisywane w pliku dziennika serwera w tle, gdy parametr log_statement jest ustawiony, jednak w tym przypadku nie jest skonfigurowany, ale komunikaty audytu są zapisywane z mocy parametru pgaudit.log, jak pokazano w demo. Dostępne są bardziej zaawansowane opcje, które spełniają wszystkie wymagania dotyczące audytu baz danych w PostgreSQL, które można skonfigurować, postępując zgodnie z oficjalną dokumentacją pgaudit tutaj lub w repozytorium github.pg_repack

Jest to ulubione rozszerzenie wielu inżynierów PostgreSQL, którzy są bezpośrednio zaangażowani w zarządzanie i utrzymywanie ogólnej kondycji klastra PostgreSQL. Powód tego zostanie omówiony nieco później, ale to rozszerzenie oferuje funkcję usuwania nadwyżek bazy danych w bazie danych PostgreSQL, co jest jednym z dokuczliwych problemów wśród bardzo dużych klastrów baz danych PostgreSQL wymagających ponownej organizacji bazy danych.

Ponieważ baza danych PostgreSQL przechodzi ciągłe i intensywne WRITES (aktualizacje i usunięcia), stare dane są oznaczane jako usunięte, podczas gdy nowa wersja wiersza jest wstawiana, ale stare dane nie są faktycznie usuwane z blok danych. Wymaga to okresowej operacji konserwacyjnej zwanej odkurzaniem, która jest zautomatyzowaną procedurą wykonywaną w tle, która usuwa wszystkie wiersze „oznaczone jako usunięte”. Ten proces jest czasami określany potocznie jako wyrzucanie śmieci.

Proces odkurzania generalnie ustępuje miejsca operacjom bazy danych w bardziej ruchliwych okresach. Najmniej restrykcyjny sposób odkurzania na korzyść operacji bazodanowych skutkuje dużą liczbą wierszy „oznaczonych jako usunięte” powodujących nieproporcjonalny wzrost baz danych, co określa się mianem „rozdęcia bazy danych”. Istnieje wymuszony proces odkurzania zwany VACUUM FULL, ale powoduje to uzyskanie blokady na wyłączność przetwarzanego obiektu bazy danych, co powoduje wstrzymanie operacji bazy danych na tym obiekcie.

pg_repack

Z tego powodu pg_repack jest hitem wśród administratorów baz danych PostgreSQL i inżynierów, ponieważ wykonuje on zadanie normalnego procesu odkurzania, ale oferuje wydajność PRÓŻNI PEŁNEJ, nie uzyskując wyłącznej blokady bazy danych obiekt, w skrócie, działa on-line. Oficjalna dokumentacja tutaj wyjaśnia więcej na temat innych metod reorganizacji bazy danych, ale szybkie demo, jak poniżej, rzuci wszystko w odpowiednie światło dla lepszego zrozumienia. Istnieje wymóg, aby tabela docelowa miała co najmniej jedną kolumnę zdefiniowaną jako KLUCZ PODSTAWOWY, co jest ogólną normą w większości konfiguracji produkcyjnych baz danych.

Demo

Podstawowe demo pokazuje instalację i użycie pg_repack w środowisku testowym. To demo używa wersji 1.4.5 pg_repack, która jest najnowszą wersją tego rozszerzenia w momencie publikacji tego bloga. Tabela demonstracyjna t1 początkowo ma 80000 wierszy, które są poddawane potężnej operacji usuwania, która usuwa co piąty wiersz tabeli. Wykonanie pg_repack pokazuje rozmiar tabeli przed i po.

mydb=# CREATE EXTENSION pg_repack;

CREATE EXTENSION



mydb=# create table t1 (no integer primary key, f_name VARCHAR(20), l_name VARCHAR(20), d_o_b date);

CREATE TABLE

mydb=# insert into t1 (select generate_series(1,1000000,1),'a'||

mydb(# generate_series(1,1000000,1),'a'||generate_series(1000000,1,-1),

mydb(# cast( now() - '1 year'::interval * random()  as date ));

INSERT 0 1000000



mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));

 pg_size_pretty

----------------

 71 MB

(1 row)



mydb=# CREATE or replace FUNCTION delete5() RETURNS void AS $$

mydb$# declare

mydb$# counter integer := 0;

mydb$# BEGIN

mydb$#

mydb$#  while counter <= 1000000

mydb$# loop

mydb$# delete from t1 where no=counter;

mydb$# counter := counter + 5;

mydb$# END LOOP;

mydb$# END;

mydb$# $$ LANGUAGE plpgsql;

CREATE FUNCTION

Funkcja delete5 usuwa 200000 wierszy z tabeli t1 za pomocą licznika, który zwiększa 5 zliczeń

mydb=# select delete5();

 delete5

------



(1 row)

mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));

 pg_size_pretty

----------------

 71 MB

(1 row)



$ pg_repack -t t1 -N -n -d mydb -p 5433

INFO: Dry run enabled, not executing repack

INFO: repacking table "public.t1"



$ pg_repack -t t1 -n -d mydb -p 5433

INFO: repacking table "public.t1"



mydb=# SELECT pg_size_pretty( pg_total_relation_size('t1'));

 pg_size_pretty

----------------

 57 MB

(1 row)

Jak pokazano powyżej, oryginalny rozmiar tabeli nie zmienia się po wykonaniu funkcji delete5, co pokazuje, że wiersze nadal istnieją w tabeli. Wykonanie pg_repack usuwa wiersze „zaznaczone jako usunięte” z tabeli t1, zmniejszając rozmiar tabeli t1 do 57 MB. Kolejną dobrą rzeczą w pg_repack jest opcja uruchomienia na sucho z flagą -N, za pomocą której można sprawdzić, co zostanie wykonane podczas rzeczywistego uruchomienia.

HypoPG

Następne interesujące rozszerzenie jest identyczne z popularną koncepcją zwaną niewidocznymi indeksami wśród zastrzeżonych serwerów baz danych. Rozszerzenie HypoPG pozwala DBA zobaczyć efekt wprowadzenia hipotetycznego indeksu (który nie istnieje) i czy poprawi wydajność jednego lub więcej zapytań, stąd nazwa HypoPG.

Stworzenie hipotetycznego indeksu nie wymaga żadnych zasobów procesora ani dysku, jednak zużywa prywatną pamięć połączenia. Ponieważ indeks hipotetyczny nie jest przechowywany w żadnych tabelach wykazu bazy danych, nie występuje więc wpływ rozrostu tabeli. Z tego powodu hipotetyczny indeks nie może być użyty w wyrażeniu EXPLAIN ANALYZE, podczas gdy zwykły EXPLAIN jest dobrym sposobem oceny, czy potencjalny indeks będzie używany przez dane problematyczne zapytanie. Oto krótkie demo wyjaśniające, jak działa HypoPG.

Demo

Zamierzam utworzyć tabelę zawierającą 100000 wierszy za pomocą generate_series i wykonać kilka prostych zapytań, aby pokazać różnicę w szacunkowych kosztach z hipotetycznymi indeksami i bez nich.

olap=# CREATE EXTENSION hypopg;

CREATE EXTENSION



olap=# CREATE TABLE stock (id integer, line text);

CREATE TABLE



olap=# INSERT INTO stock SELECT i, 'line ' || i FROM generate_series(1, 100000) i;

INSERT 0 100000



olap=# ANALYZE STOCK;

ANALYZE



olap=#  EXPLAIN SELECT line FROM stock WHERE id = 1;

                       QUERY PLAN

---------------------------------------------------------

 Seq Scan on stock  (cost=0.00..1791.00 rows=1 width=10)

   Filter: (id = 1)

(2 rows)

olap=# SELECT * FROM hypopg_create_index('CREATE INDEX ON stock (id)') ;

 indexrelid |       indexname

------------+-----------------------

      25398 | <25398>btree_stock_id

(1 row)



olap=# EXPLAIN SELECT line FROM stock WHERE id = 1;

                                     QUERY PLAN

------------------------------------------------------------------------------------

 Index Scan using <25398>btree_stock_id on stock  (cost=0.04..8.06 rows=1 width=10)

   Index Cond: (id = 1)

(2 rows)



olap=# EXPLAIN ANALYZE SELECT line FROM stock WHERE id = 1;

                                             QUERY PLAN

----------------------------------------------------------------------------------------------------

 Seq Scan on stock  (cost=0.00..1791.00 rows=1 width=10) (actual time=0.028..41.877 rows=1 loops=1)

   Filter: (id = 1)

   Rows Removed by Filter: 99999

 Planning time: 0.057 ms

 Execution time: 41.902 ms

(5 rows)



olap=# SELECT indexname, pg_size_pretty(hypopg_relation_size(indexrelid))

olap-#   FROM hypopg_list_indexes() ;

       indexname       | pg_size_pretty

-----------------------+----------------

 <25398>btree_stock_id | 2544 kB

(1 row)



olap=# SELECT pg_size_pretty(pg_relation_size('stock'));

 pg_size_pretty

----------------

 4328 kB

(1 row)

Powyższy rysunek pokazuje, jak szacowany całkowity koszt można zmniejszyć z 1791 do 8,06, dodając indeks do pola „id” tabeli w celu optymalizacji prostego zapytania. Udowadnia również, że indeks nie jest tak naprawdę używany, gdy zapytanie jest wykonywane z funkcją EXPLAIN ANALYZE, która wykonuje zapytanie w czasie rzeczywistym. Istnieje również sposób, aby dowiedzieć się w przybliżeniu, ile miejsca na dysku zajmuje indeks, korzystając z funkcji hypopg_list_indexes rozszerzenia.

HypoPG ma kilka innych funkcji do zarządzania hipotetycznymi indeksami, a ponadto oferuje również sposób sprawdzenia, czy partycjonowanie tabeli poprawi wydajność zapytań pobierających duży zestaw danych. Istnieje hipotetyczna opcja partycjonowania rozszerzenia HypoPG, a więcej z nich można śledzić, odnosząc się do oficjalnej dokumentacji.

Wnioski

Jak wspomniano w części pierwszej, PostgreSQL ewoluował przez lata, stając się coraz większy, lepszy i szybszy dzięki szybkiemu rozwojowi zarówno w natywnym kodzie źródłowym, jak i rozszerzeniach plug and play. Wersja open source nowego PostgreSQL może być najbardziej odpowiednia dla wielu sklepów IT, które korzystają z jednego z głównych własnościowych serwerów baz danych, aby zredukować wydatki na IT CAPEX i OPEX.

Istnieje wiele rozszerzeń PostgreSQL, które oferują funkcje od monitorowania po wysoką dostępność i od skalowania po zrzucanie binarnych plików danych do formatu czytelnego dla człowieka. Mamy nadzieję, że powyższe demonstracje rzuciły ogromne światło na maksymalny potencjał i moc bazy danych PostgreSQL.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mapowanie typu szeregowego PostgreSQL z adnotacjami Hibernate

  2. Wyjaśnienie JSONB wprowadzone przez PostgreSQL

  3. Jak zapobiec usunięciu pierwszego wiersza w tabeli (PostgreSQL)?

  4. Przyznać uprawnienia do przyszłych tabel w PostgreSQL?

  5. Nie udało się znaleźć funkcji konwersji z nieznanej na tekst