Esta é uma continuação da minha entrada de blog anterior, na qual abordei um tópico das Extensões do PostgreSQL. As extensões do PostgreSQL são um conjunto plug and play de aprimoramentos que adicionam um conjunto extra de recursos a um cluster do PostgreSQL. Alguns desses recursos são tão simples quanto ler ou gravar em um banco de dados externo, enquanto outros podem ser uma solução sofisticada para implementar replicação de banco de dados, monitoramento etc.
O PostgreSQL evoluiu ao longo dos anos de um simples ORDBMS de código aberto para um poderoso sistema de banco de dados com mais de 30 anos de desenvolvimento ativo, oferecendo confiabilidade, desempenho e todos os recursos compatíveis com ACID. Com o PostgreSQL 12 lançado há alguns meses, este software de banco de dados está ficando cada vez maior, melhor e mais rápido.
Ocasionalmente, as extensões precisavam ser adicionadas a um cluster PostgreSQL para obter funcionalidades aprimoradas que não estavam disponíveis no código nativo, porque não foram desenvolvidas devido a restrições de tempo ou devido a evidências insuficientes de banco de dados de casos extremos problemas. Vou discutir algumas das minhas extensões favoritas em nenhuma ordem específica, com algumas demos que são usadas por desenvolvedores e DBAs.
Algumas dessas extensões podem precisar ser incluídas no parâmetro do servidor shared_preload_libraries como uma lista separada por vírgulas a ser pré-carregada na inicialização do servidor. Embora a maioria das extensões esteja incluída no módulo contrib do código-fonte, algumas precisam ser baixadas de um site externo dedicado apenas às extensões do PostgreSQL chamado PostgreSQL Extension Network.
Nesta série de blog de duas partes, discutiremos as extensões usadas para acessar dados (postgres_fwd) e reduzir ou arquivar bancos de dados (pg_partman). Extensões adicionais serão discutidas na segunda parte.
postgres_fdw
O postgres_fdw é uma extensão externa de encapsulamento de dados que pode ser usada para acessar dados armazenados em servidores PostgreSQL externos. Essa extensão é semelhante a uma extensão mais antiga chamada dblink, mas difere de sua antecessora por oferecer sintaxe compatível com os padrões e melhor desempenho.
Os componentes importantes do postgres_fdw são um servidor, um mapeamento de usuário e uma tabela externa. Há uma pequena sobrecarga adicionada ao custo real da execução de consultas em servidores remotos, que é a sobrecarga de comunicação. A extensão postgres_fdw também é capaz de se comunicar com um servidor remoto com uma versão até o PostgreSQL 8.3, sendo compatível com versões anteriores.
Demonstração
A demonstração exibirá uma conexão do PostgreSQL 12 a um banco de dados PostgreSQL 11. As configurações do pg_hba.conf já foram configuradas para que os servidores conversem entre si. Os arquivos de controle de extensão precisam ser carregados no diretório inicial compartilhado do PostgreSQL antes de criar a extensão de Dentro de um cluster PostgreSQL.
Servidor Remoto:
$ /usr/local/pgsql-11.3/bin/psql -p 5432 -d db_replica postgres
psql (11.3)
Type "help" for help.
db_replica=# create table t1 (sno integer, emp_id text);
CREATE TABLE
db_replica=# \dt t1
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | t1 | table | postgres
db_replica=# insert into t1 values (1, 'emp_one');
INSERT 0 1
db_replica=# select * from t1;
sno | emp_id
-----+---------
1 | emp_one
(1 row)
Servidor de origem:
$ /database/pgsql-12.0/bin/psql -p 5732 postgres
psql (12.0)
Type "help" for help.
postgres=# CREATE EXTENSION postgres_fdw;
CREATE EXTENSION
postgres=# CREATE SERVER remote_server
postgres-# FOREIGN DATA WRAPPER postgres_fdw
postgres-# OPTIONS (host '192.168.1.107', port '5432', dbname 'db_replica');
CREATE SERVER
postgres=# CREATE USER MAPPING FOR postgres
postgres-# SERVER remote_server
postgres-# OPTIONS (user 'postgres', password 'admin123');
CREATE USER MAPPING
postgres=# CREATE FOREIGN TABLE remote_t1
postgres-# (sno integer, emp_id text)
postgres-# server remote_server
postgres-# options (schema_name 'public', table_name 't1');
CREATE FOREIGN TABLE
postgres=# select * from remote_t1;
sno | emp_id
-----+---------
1 | emp_one
(1 row)
postgres=# insert into remote_t1 values (2,'emp_two');
INSERT 0 1
postgres=# select * from remote_t1;
sno | emp_id
-----+---------
1 | emp_one
2 | emp_two
(2 rows)
A operação WRITE do servidor de origem reflete a tabela do servidor remoto imediatamente. Também existe uma extensão semelhante chamada oracle_fdw que permite o acesso READ e WRITE entre as tabelas PostgreSQL e Oracle. Além disso, há outra extensão chamada file_fdw que permite o acesso a dados de arquivos simples no disco. Por favor, consulte a documentação oficial do postgres_fdw publicada aqui, para mais informações e detalhes.
pg_partman
À medida que os bancos de dados e as tabelas crescem, há sempre a necessidade de reduzi-los, arquivar dados desnecessários ou pelo menos particionar tabelas em vários fragmentos menores. Isso ocorre para que o otimizador de consulta visite apenas as partes da tabela que atendem às condições de consulta, em vez de varrer todo o heap de tabelas.
O PostgreSQL oferece recursos de particionamento há muito tempo, incluindo técnicas de Intervalo, Lista, Hash e Sub-particionamento. No entanto, requer muitos esforços de administração e gerenciamento, como definir tabelas filhas que herdam propriedades de uma tabela pai para se tornarem suas partições, criar funções de gatilho para redirecionar dados para uma partição e criar gatilhos para chamar essas funções, etc. onde o pg_partman entra em ação, onde todos esses problemas são resolvidos automaticamente.
Demonstração
Vou mostrar uma demonstração rápida de como configurar e inserir dados de amostra. Você verá como os dados inseridos na tabela principal são redirecionados automaticamente para as partições apenas configurando pg_partman. É importante que a coluna da chave de partição não seja nula.
db_replica=# show shared_preload_libraries;
shared_preload_libraries
--------------------------
pg_partman_bgw
(1 row)
db_replica=# CREATE SCHEMA partman;
CREATE SCHEMA
db_replica=# CREATE EXTENSION pg_partman SCHEMA partman;
CREATE EXTENSION
db_replica=# CREATE ROLE partman WITH LOGIN;
CREATE ROLE
db_replica=# GRANT ALL ON SCHEMA partman TO partman;
GRANT
db_replica=# GRANT ALL ON ALL TABLES IN SCHEMA partman TO partman;
GRANT
db_replica=# GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO partman;
GRANT
db_replica=# GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO partman;
GRANT
db_replica=# GRANT ALL ON SCHEMA PUBLIC TO partman;
GRANT
db_replica=# create table t1 (sno integer, emp_id varchar, date_of_join date not null);
db_replica=# \d
List of relations
Schema | Name | Type | Owner
--------+------+-------+----------
public | t1 | table | postgres
(1 row)
db_replica=# \d t1
Table "public.t1"
Column | Type | Collation | Nullable | Default
--------------+-------------------+-----------+----------+---------
sno | integer | | |
emp_id | character varying | | |
date_of_join | date | | not null |
db_replica=# SELECT partman.create_parent('public.t1', 'date_of_join', 'partman', 'yearly');
create_parent
---------------
t
(1 row)
db_replica=# \d+ t1
Table "public.t1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------------+-------------------+-----------+----------+---------+----------+--------------+-------------
sno | integer | | | | plain | |
emp_id | character varying | | | | extended | |
date_of_join | date | | not null | | plain | |
Triggers:
t1_part_trig BEFORE INSERT ON t1 FOR EACH ROW EXECUTE PROCEDURE t1_part_trig_func()
Child tables: t1_p2015,
t1_p2016,
t1_p2017,
t1_p2018,
t1_p2019,
t1_p2020,
t1_p2021,
t1_p2022,
t1_p2023
db_replica=# select * from t1;
sno | emp_id | date_of_join
-----+--------+--------------
(0 rows)
db_replica=# select * from t1_p2019;
sno | emp_id | date_of_join
-----+--------+--------------
(0 rows)
db_replica=# select * from t1_p2020;
sno | emp_id | date_of_join
-----+--------+--------------
(0 rows)
db_replica=# insert into t1 values (1,'emp_one','01-06-2019');
INSERT 0 0
db_replica=# insert into t1 values (2,'emp_two','01-06-2020');
INSERT 0 0
db_replica=# select * from t1;
sno | emp_id | date_of_join
-----+---------+--------------
1 | emp_one | 2019-01-06
2 | emp_two | 2020-01-06
(2 rows)
db_replica=# select * from t1_p2019;
sno | emp_id | date_of_join
-----+---------+--------------
1 | emp_one | 2019-01-06
(1 row)
db_replica=# select * from t1_p2020;
sno | emp_id | date_of_join
-----+---------+--------------
2 | emp_two | 2020-01-06
(1 row)
Esta é uma técnica de particionamento simples, mas cada uma das partições simples acima pode ser dividida em sub-partições. Por favor, verifique a documentação oficial do pg_partman publicada aqui, para mais recursos e funções que ele oferece.
Conclusão
A segunda parte deste blog discutirá outras extensões do PostgreSQL como pgAudit, pg_repack e HypoPG.