PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Le mie estensioni PostgreSQL preferite - Parte seconda

Questa è la seconda parte del mio blog "Le mie estensioni PostgreSQL preferite" in cui ti avevo presentato due estensioni PostgreSQL, postgres_fdw e pg_partman. In questa parte ne esplorerò altri tre.

pgAudit

La prossima estensione di interesse di PostgreSQL ha lo scopo di soddisfare i requisiti di audit di vari enti di certificazione governativi, finanziari e di altro tipo come ISO, BSI e FISCAM, ecc. La funzione di registrazione standard che PostgreSQL offre in modo nativo with log_statement =all è utile per il monitoraggio, ma non fornisce i dettagli necessari per conformarsi o affrontare l'audit. L'estensione pgAudit si concentra sui dettagli di ciò che è accaduto sotto il cofano, mentre un database stava soddisfacendo una richiesta di applicazione.

Un audit trail o registro di audit viene creato e aggiornato da una funzione di registrazione standard fornita da PostgreSQL, che fornisce una registrazione dettagliata di sessioni e/o audit degli oggetti. L'audit trail creato da pgAudit può diventare di dimensioni enormi a seconda delle impostazioni di audit, quindi è necessario prestare attenzione per decidere in anticipo cosa e quanto auditing è necessario. Una breve demo nella sezione seguente mostra come pgAudit è configurato e utilizzato.

Il log trail viene creato all'interno del log del cluster di database PostgreSQL che si trova nella posizione PGDATA/log ma i messaggi del log di audit sono preceduti da un'etichetta "AUDIT:" per distinguere tra i normali messaggi di sfondo del database e il log di audit record.

Demo

La documentazione ufficiale di pgAudit spiega che esiste una versione separata di pgAudit per ogni versione principale di PostgreSQL al fine di supportare le nuove funzionalità introdotte in ogni rilascio di PostgreSQL. La versione di PostgreSQL in questa demo è 11, quindi la versione di pgAudit sarà dal ramo 1.3.X. Il pgaudit.log è il parametro fondamentale da impostare che controlla quali classi di istruzioni verranno registrate. Può essere impostato con un SET per un livello di sessione o all'interno del file postgresql.conf da applicare globalmente.

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>

Le voci di log, come mostrato nella demo precedente, vengono scritte nel file di log in background del server solo quando è impostato il parametro log_statement, tuttavia in questo caso non è configurato ma i messaggi di audit vengono scritti in virtù del parametro pgaudit.log come evidenziato nella demo. Sono disponibili opzioni più potenti per soddisfare tutti i requisiti di controllo del database all'interno di PostgreSQL, che possono essere configurate seguendo la documentazione ufficiale di pgaudit qui o su github repository.pg_repack

Questa è un'estensione preferita da molti ingegneri PostgreSQL che sono coinvolti direttamente nella gestione e nel mantenimento dello stato generale di un cluster PostgreSQL. Il motivo sarà discusso un po 'più avanti, ma questa estensione offre la funzionalità per rimuovere il bloat del database all'interno di un database PostgreSQL, che è una delle preoccupazioni fastidiose tra i cluster di database PostgreSQL molto grandi che richiedono la riorganizzazione del database.

Poiché un database PostgreSQL è sottoposto a SCRITTE (aggiornamenti ed eliminazioni) costanti e pesanti, i vecchi dati vengono contrassegnati come eliminati mentre viene inserita la nuova versione della riga, ma i vecchi dati non vengono effettivamente cancellati da un blocco dati. Ciò richiede un'operazione di manutenzione periodica denominata vacuuming, che è una procedura automatizzata eseguita in background che cancella tutte le righe "contrassegnate come eliminate". Questo processo viene talvolta definito raccolta dei rifiuti in termini colloquiali.

Il processo di aspirazione generalmente lascia il posto alle operazioni del database durante i periodi di maggiore affluenza. Il modo meno restrittivo di passare l'aspirapolvere a favore delle operazioni del database si traduce in un gran numero di righe "contrassegnate come eliminate" che causano una crescita sproporzionata dei database denominata "rigonfiamento del database". Esiste un processo di eliminazione forzata chiamato VACUUM FULL, ma ciò comporta l'acquisizione di un blocco esclusivo sull'oggetto del database in elaborazione, bloccando le operazioni del database su quell'oggetto.

pg_repack

È per questo motivo che pg_repack è un successo tra i DBA e gli ingegneri di PostgreSQL, perché svolge il lavoro di un normale processo di aspirazione ma offre un'efficienza di VACUUM FULL non acquisendo un blocco esclusivo su un database oggetto, in breve, funziona online. La documentazione ufficiale qui spiega di più sugli altri metodi di riorganizzazione di un database, ma una rapida demo come di seguito metterà le cose nella luce appropriata per una migliore comprensione. È necessario che la tabella di destinazione abbia almeno una colonna definita come CHIAVE PRIMARIA, che è una norma generale nella maggior parte delle configurazioni di database di produzione.

Demo

La demo di base mostra l'installazione e l'utilizzo di pg_repack in un ambiente di test. Questa demo utilizza la versione 1.4.5 di pg_repack che è l'ultima versione di questa estensione al momento della pubblicazione di questo blog. Una tabella demo t1 ha inizialmente 80000 righe che subiscono un'operazione massiccia di eliminazione, che elimina ogni 5a riga della tabella. Un'esecuzione di pg_repack mostra la dimensione della tabella prima e dopo.

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

La funzione delete5 elimina 200000 righe dalla tabella t1 utilizzando un contatore che incrementa 5 conteggi

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)

Come mostrato sopra, la dimensione originale della tabella non cambia dopo l'esecuzione della funzione delete5, che mostra che le righe esistono ancora nella tabella. L'esecuzione di pg_repack cancella quelle righe "contrassegnate come eliminate" dalla tabella t1 riducendo la dimensione della tabella t1 a 57 MB. Un'altra cosa buona di pg_repack è un'opzione per la corsa a secco con il flag -N, utilizzando la quale puoi controllare cosa verrà eseguito durante una corsa effettiva.

HypoPG

La prossima estensione interessante è identica a un concetto popolare chiamato indici invisibili tra i server di database proprietari. L'estensione HypoPG consente a un DBA di vedere l'effetto dell'introduzione di un ipotetico indice (che non esiste) e se migliorerà le prestazioni di una o più query, da cui il nome HypoPG.

La creazione di un ipotetico indice non richiede CPU o risorse disco, tuttavia consuma la memoria privata di una connessione. Poiché l'ipotetico indice non è archiviato in nessuna tabella del catalogo del database, non vi è alcun impatto sull'espansione della tabella. È per questo motivo che un indice ipotetico non può essere utilizzato in un'istruzione EXPLAIN ANALYZE mentre un semplice EXPLAIN è un buon modo per valutare se un potenziale indice verrà utilizzato da una determinata query problematica. Ecco una rapida demo per spiegare come funziona HypoPG.

Demo

Creerò una tabella contenente 100000 righe utilizzando generate_series ed eseguirò un paio di semplici query per mostrare la differenza nelle stime dei costi con e senza indici ipotetici.

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)

La mostra sopra mostra come è possibile ridurre il costo totale stimato da 1791 a 8,06 aggiungendo un indice al campo "id" della tabella per ottimizzare una semplice query. Dimostra inoltre che l'indice non viene realmente utilizzato quando la query viene eseguita con un'ANALISI ESPLICA che esegue la query in tempo reale. C'è anche un modo per scoprire approssimativamente quanto spazio su disco occupa l'indice utilizzando la funzione hypopg_list_indexes dell'estensione.

L'HypoPG ha alcune altre funzioni per gestire gli indici ipotetici e in aggiunta a ciò, offre anche un modo per scoprire se il partizionamento di una tabella migliorerà le prestazioni delle query che recuperano un set di dati di grandi dimensioni. Esiste un'ipotetica opzione di partizionamento dell'estensione HypoPG e più può essere seguita facendo riferimento alla documentazione ufficiale.

Conclusione

Come affermato nella prima parte, PostgreSQL si è evoluto nel corso degli anni diventando solo più grande, migliore e più veloce con un rapido sviluppo sia nel codice sorgente nativo che nelle estensioni plug and play. Una versione open source del nuovo PostgreSQL può essere più adatta per molti negozi IT che eseguono uno dei principali server di database proprietari, al fine di ridurre il loro IT CAPEX e OPEX.

Esistono molte estensioni PostgreSQL che offrono funzionalità che vanno dal monitoraggio all'alta disponibilità e dal ridimensionamento al dump di file di dati binari in un formato leggibile dall'uomo. Si spera che le dimostrazioni di cui sopra abbiano gettato un'enorme luce sul potenziale massimo e sulla potenza di un database PostgreSQL.