PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Minhas extensões favoritas do PostgreSQL - Parte dois

Esta é a segunda parte do meu blog “Minhas Extensões PostgreSQL Favoritas”, na qual apresentei duas extensões PostgreSQL, postgres_fdw e pg_partman. Nesta parte vou explorar mais três.

pgAuditoria

A próxima extensão de interesse do PostgreSQL é para atender aos requisitos de auditoria de vários órgãos governamentais, financeiros e outros órgãos de certificação, como ISO, BSI e FISCAM, etc. O recurso de registro padrão que o PostgreSQL oferece nativamente com log_statement =all é útil para monitoramento, mas não fornece os detalhes necessários para cumprir ou enfrentar a auditoria. A extensão pgAudit se concentra nos detalhes do que aconteceu nos bastidores, enquanto um banco de dados estava atendendo a uma solicitação de aplicativo.

Uma trilha de auditoria ou log de auditoria é criada e atualizada por um recurso de log padrão fornecido pelo PostgreSQL, que fornece log de auditoria detalhado de sessão e/ou objeto. A trilha de auditoria criada pelo pgAudit pode ficar enorme dependendo das configurações de auditoria, portanto, deve-se tomar cuidado para decidir o que e quanta auditoria é necessária com antecedência. Uma breve demonstração na seção a seguir mostra como o pgAudit é configurado e colocado em uso.

A trilha de log é criada dentro do log de cluster do banco de dados PostgreSQL encontrado no local PGDATA/log, mas as mensagens de log de auditoria são prefixadas com um rótulo “AUDIT:” para distinguir entre mensagens regulares de segundo plano do banco de dados e log de auditoria registros.

Demonstração

A documentação oficial do pgAudit explica que existe uma versão separada do pgAudit para cada versão principal do PostgreSQL para suportar novas funcionalidades introduzidas em cada versão do PostgreSQL. A versão do PostgreSQL nesta demonstração é 11, então a versão do pgAudit será do branch 1.3.X. O pgaudit.log é o parâmetro fundamental a ser configurado que controla quais classes de instruções serão registradas. Ele pode ser definido com um SET para um nível de sessão ou dentro do arquivo postgresql.conf para ser aplicado 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>

As entradas de log, conforme mostrado na demonstração acima, são gravadas apenas no arquivo de log de fundo do servidor quando o parâmetro log_statement é definido, porém neste caso não está configurado, mas as mensagens de auditoria são gravadas em virtude do parâmetro pgaudit.log conforme evidenciado na demonstração. Existem opções mais poderosas disponíveis para atender a todos os seus requisitos de auditoria de banco de dados no PostgreSQL, que podem ser configurados seguindo a documentação oficial do pgaudit aqui ou no repositório do github.pg_repack

Esta é uma extensão favorita entre muitos engenheiros do PostgreSQL que estão envolvidos diretamente no gerenciamento e manutenção da saúde geral de um cluster PostgreSQL. A razão para isso será discutida um pouco mais tarde, mas esta extensão oferece a funcionalidade de remover o inchaço do banco de dados dentro de um banco de dados PostgreSQL, que é uma das preocupações irritantes entre clusters de banco de dados PostgreSQL muito grandes que exigem reorganização do banco de dados.

Como um banco de dados PostgreSQL sofre ESCRITAS constantes e pesadas (atualizações e exclusões), os dados antigos são marcados como excluídos enquanto a nova versão da linha é inserida, mas os dados antigos não são realmente apagados de um bloco de dados. Isso requer uma operação de manutenção periódica chamada aspiração, que é um procedimento automatizado executado em segundo plano que limpa todas as linhas “marcadas como excluídas”. Esse processo às vezes é chamado de coleta de lixo em termos coloquiais.

O processo de limpeza geralmente dá lugar às operações do banco de dados durante os períodos mais movimentados. A maneira menos restritiva de limpar a favor das operações do banco de dados resulta em um grande número de linhas “marcadas como excluídas” fazendo com que os bancos de dados cresçam desproporcionalmente, conhecido como “inchaço do banco de dados”. Existe um processo de limpeza forçado chamado VACUUM FULL, mas isso resulta na aquisição de um bloqueio exclusivo no objeto de banco de dados que está sendo processado, parando as operações de banco de dados nesse objeto.

pg_repack

É por isso que o pg_repack é um sucesso entre os DBAs e engenheiros do PostgreSQL, pois faz o trabalho de um processo normal de aspiração, mas oferece uma eficiência de VACUUM FULL por não adquirir um bloqueio exclusivo em um banco de dados objeto, em suma, funciona online. A documentação oficial aqui explica mais sobre os outros métodos de reorganização de um banco de dados, mas uma demonstração rápida, como abaixo, colocará as coisas na luz apropriada para melhor compreensão. Existe a exigência de que a tabela de destino tenha pelo menos uma coluna definida como PRIMARY KEY, que é uma norma geral na maioria das configurações de banco de dados de produção.

Demonstração

A demonstração básica mostra a instalação e uso do pg_repack em um ambiente de teste. Esta demonstração usa a versão 1.4.5 do pg_repack, que é a versão mais recente dessa extensão no momento da publicação deste blog. Uma tabela de demonstração t1 inicialmente possui 80.000 linhas que passam por uma operação massiva de exclusão, que exclui a cada 5 linhas da tabela. Uma execução de pg_repack mostra o tamanho da tabela antes e depois.

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

A função delete5 exclui 200.000 linhas da tabela t1 usando um contador que incrementa 5 contagens
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)

Como mostrado acima, o tamanho original da tabela não muda após a execução da função delete5 , que mostra que as linhas ainda existem na tabela. A execução de pg_repack limpa as linhas 'marcadas como excluídas' da tabela t1, reduzindo o tamanho da tabela t1 para 57 MBs. Outra coisa boa sobre o pg_repack é uma opção de simulação com o sinalizador -N, com o qual você pode verificar o que será executado durante uma execução real.

HypoPG

A próxima extensão interessante é idêntica a um conceito popular chamado índices invisíveis entre servidores de banco de dados proprietários. A extensão HypoPG permite que um DBA veja o efeito da introdução de um índice hipotético (que não existe) e se ele melhorará o desempenho de uma ou mais consultas, daí o nome HypoPG.

A criação de um índice hipotético não requer nenhum recurso de CPU ou disco, mas consome a memória privada de uma conexão. Como o índice hipotético não é armazenado em nenhuma tabela de catálogo de banco de dados, não há impacto do inchaço da tabela. É por esse motivo que um índice hipotético não pode ser usado em uma instrução EXPLAIN ANALYZE enquanto um EXPLAIN simples é uma boa maneira de avaliar se um índice potencial será usado por uma determinada consulta problemática. Aqui está uma demonstração rápida para explicar como o HypoPG funciona.

Demonstração

Vou criar uma tabela contendo 100.000 linhas usando generate_series e executar algumas consultas simples para mostrar a diferença nas estimativas de custo com e sem índices hipotéticos.

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)

A exibição acima mostra como o custo total estimado pode ser reduzido de 1791 para 8,06 adicionando um índice ao campo “id” da tabela para otimizar uma consulta simples. Também prova que o índice não é realmente usado quando a consulta é executada com um EXPLAIN ANALYZE que executa a consulta em tempo real. Há também uma maneira de descobrir aproximadamente quanto espaço em disco o índice ocupa usando a função hypopg_list_indexes da extensão.

O HypoPG tem algumas outras funções para gerenciar índices hipotéticos e, além disso, também oferece uma maneira de descobrir se o particionamento de uma tabela melhorará o desempenho das consultas que buscam um grande conjunto de dados. Existe uma opção hipotética de particionamento da extensão HypoPG e mais dela pode ser seguida consultando a documentação oficial.

Conclusão

Como dito na primeira parte, o PostgreSQL evoluiu ao longo dos anos, ficando cada vez maior, melhor e mais rápido com o desenvolvimento rápido tanto no código-fonte nativo quanto nas extensões plug and play. Uma versão de código aberto do novo PostgreSQL pode ser mais adequada para muitas lojas de TI que estão executando um dos principais servidores de banco de dados proprietários, a fim de reduzir seu CAPEX e OPEX de TI.

Existem muitas extensões do PostgreSQL que oferecem recursos que variam de monitoramento a alta disponibilidade e de dimensionamento para despejar arquivos de dados binários em formato legível por humanos. Espera-se que as demonstrações acima tenham esclarecido enormemente o potencial e o poder máximos de um banco de dados PostgreSQL.