Otimizando Foreign Data Wrappers do PostgreSQL para Integração de Múltiplos Bancos de Dados
Use FDWs do PostgreSQL para consultar bancos de dados remotos com segurança, ajustar pushdown e evitar armadilhas comuns de desempenho em federação.
Otimizando Foreign Data Wrappers do PostgreSQL para Integração Multi-Banco
Os Foreign Data Wrappers do PostgreSQL ajudam quando seus dados estão em mais de um lugar e você precisa consultá-los sem copiar tudo primeiro. FDWs podem fazer tabelas remotas parecerem locais, mas o desempenho e o comportamento de transações dependem fortemente do wrapper, da rede e da forma da consulta.
O que são Foreign Data Wrappers?
FDW implementa o padrão SQL/MED (Management of External Data), fornecendo:
- Acesso transparente: Consulte dados remotos usando SQL padrão
- Tabelas virtuais: Nenhuma duplicação de dados necessária
- Leituras remotas ao vivo: Consultas leem da fonte remota em vez de uma cópia local
- Capacidade de junção: Combine dados locais e remotos
- Operações de escrita: Alguns wrappers suportam
INSERT,UPDATEeDELETE
Casos de Uso Comuns
- Migração de Banco de Dados: Acesse sistemas legados durante a migração
- Arquitetura Multi-inquilino: Consulte entre bancos de dados de inquilinos
- Agregação de Dados: Combine dados de múltiplas fontes
- Nuvem Híbrida: Conecte bancos de dados locais e na nuvem
- Relatórios: Crie um banco de dados de relatórios centralizado
- Microsserviços: Consulte entre limites de serviço
Foreign Data Wrappers Disponíveis
postgresql_fdw (Integrado)
- Conecte-se a outros bancos de dados PostgreSQL
- Suporte completo de recursos
- Melhor desempenho
mysql_fdw
- Conecte-se a MySQL/MariaDB
- Suporte de leitura e escrita
oracle_fdw
- Conecte-se a bancos de dados Oracle
- Comumente usado através da extensão de código aberto
oracle_fdw, com bibliotecas cliente Oracle instaladas separadamente
mongodb_fdw
- Acesse coleções MongoDB
- Integração de dados JSON
file_fdw (Integrado)
- Leia arquivos CSV e de texto
- Análise de arquivos de log
Outros
- redis_fdw, sqlite_fdw, couchdb_fdw, etc.
Configurando postgres_fdw
Passo 1: Instalar Extensão
-- No banco de dados local
CREATE EXTENSION postgres_fdw;
Passo 2: Criar Servidor Remoto
CREATE SERVER remote_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'remote-db.example.com',
port '5432',
dbname 'production_db',
fetch_size '10000'
);
Passo 3: Criar Mapeamento de Usuário
-- Mapear usuários locais para credenciais remotas
CREATE USER MAPPING FOR postgres
SERVER remote_db
OPTIONS (
user 'remote_user',
password 'secure_password'
);
-- Mapear todos os usuários locais
CREATE USER MAPPING FOR PUBLIC
SERVER remote_db
OPTIONS (
user 'readonly_user',
password 'readonly_pass'
);
Passo 4: Criar Tabelas Estrangeiras
Definição manual de tabela:
CREATE FOREIGN TABLE remote_users (
id INTEGER,
username VARCHAR(50),
email VARCHAR(100),
created_at TIMESTAMP
)
SERVER remote_db
OPTIONS (schema_name 'public', table_name 'users');
Importar esquema inteiro:
IMPORT FOREIGN SCHEMA public
FROM SERVER remote_db
INTO local_schema;
Importar tabelas específicas:
IMPORT FOREIGN SCHEMA public
LIMIT TO (users, orders, products)
FROM SERVER remote_db
INTO public;
Passo 5: Consultar Dados Estrangeiros
-- Consulta simples
SELECT * FROM remote_users WHERE created_at > NOW() - INTERVAL '7 days';
-- Juntar dados locais e remotos
SELECT
l.order_id,
l.amount,
r.username,
r.email
FROM local_orders l
JOIN remote_users r ON l.user_id = r.id
WHERE l.status = 'pending';
Configuração Avançada
Opções de Ajuste de Desempenho
CREATE SERVER fast_remote
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'db.example.com',
port '5432',
dbname 'mydb',
-- Tamanho de busca: linhas recuperadas por viagem de ida e volta
fetch_size '50000',
-- Habilitar otimizações de pushdown de consulta
use_remote_estimate 'true',
-- Reutilizar conexões de servidor remoto dentro de sessões PostgreSQL
keep_connections 'on',
-- Execução de consulta paralela
parallel_commit 'on',
parallel_abort 'on'
);
Opções em Nível de Tabela
CREATE FOREIGN TABLE optimized_table (
id INTEGER,
data TEXT
)
SERVER remote_db
OPTIONS (
schema_name 'public',
table_name 'large_table',
-- Substituir tamanho de busca para esta tabela
fetch_size '100000',
-- Usar estimativas remotas para melhor planejamento de consulta
use_remote_estimate 'true'
);
Opções em Nível de Coluna
CREATE FOREIGN TABLE mapped_columns (
local_id INTEGER OPTIONS (column_name 'remote_user_id'),
local_name TEXT OPTIONS (column_name 'remote_username')
)
SERVER remote_db
OPTIONS (table_name 'users');
Operações de Escrita
Habilitar Operações de Escrita
-- Conceder permissões
GRANT INSERT, UPDATE, DELETE ON remote_users TO app_user;
-- Inserir dados
INSERT INTO remote_users (username, email)
VALUES ('newuser', '[email protected]');
-- Atualizar dados
UPDATE remote_users
SET email = '[email protected]'
WHERE username = 'newuser';
-- Excluir dados
DELETE FROM remote_users WHERE username = 'newuser';
Transações Entre Bancos de Dados
BEGIN;
-- Inserir na tabela local
INSERT INTO local_orders (user_id, amount) VALUES (123, 99.99);
-- Atualizar tabela remota
UPDATE remote_users SET last_order = NOW() WHERE id = 123;
-- Ambas as operações confirmadas juntas
COMMIT;
O PostgreSQL coordena o trabalho remoto através do FDW, mas você não deve assumir que todo wrapper oferece garantias completas de transação distribuída. Para postgres_fdw, revise a opção de servidor two_phase_commit se precisar de comportamento de confirmação em duas fases e teste a recuperação de falhas antes de confiar nela para escritas críticas.
Federação Multi-Banco
Conectando Múltiplos Bancos de Dados
-- Conectar ao banco de dados de produção
CREATE SERVER prod_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'prod.example.com', dbname 'production');
CREATE USER MAPPING FOR PUBLIC SERVER prod_db
OPTIONS (user 'readonly', password 'pass1');
-- Conectar ao banco de dados de análise
CREATE SERVER analytics_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'analytics.example.com', dbname 'warehouse');
CREATE USER MAPPING FOR PUBLIC SERVER analytics_db
OPTIONS (user 'readonly', password 'pass2');
-- Conectar ao banco de dados de arquivo
CREATE SERVER archive_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'archive.example.com', dbname 'historical');
CREATE USER MAPPING FOR PUBLIC SERVER archive_db
OPTIONS (user 'readonly', password 'pass3');
Visões Unificadas Entre Bancos de Dados
-- Importar tabelas
IMPORT FOREIGN SCHEMA public
LIMIT TO (current_orders)
FROM SERVER prod_db INTO public;
IMPORT FOREIGN SCHEMA public
LIMIT TO (archived_orders)
FROM SERVER archive_db INTO public;
-- Criar visão unificada
CREATE VIEW all_orders AS
SELECT *, 'current' AS source FROM current_orders
UNION ALL
SELECT *, 'archived' AS source FROM archived_orders;
-- Consultar em todos os bancos de dados
SELECT
source,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM all_orders
WHERE created_at > '2024-01-01'
GROUP BY source;
Conectando ao MySQL
Instalar mysql_fdw
# Os nomes dos pacotes variam de acordo com a versão do PostgreSQL e o repositório.
# No Debian/Ubuntu, pesquise primeiro:
apt search mysql-fdw
# Em seguida, instale o pacote que corresponde à sua versão principal do PostgreSQL.
sudo apt install postgresql-16-mysql-fdw
Configurar Conexão MySQL
CREATE EXTENSION mysql_fdw;
CREATE SERVER mysql_server
FOREIGN DATA WRAPPER mysql_fdw
OPTIONS (
host 'mysql-db.example.com',
port '3306'
);
CREATE USER MAPPING FOR PUBLIC
SERVER mysql_server
OPTIONS (
username 'mysql_user',
password 'mysql_pass'
);
CREATE FOREIGN TABLE mysql_products (
id INTEGER,
name VARCHAR(100),
price DECIMAL(10,2)
)
SERVER mysql_server
OPTIONS (dbname 'ecommerce', table_name 'products');
-- Consultar dados MySQL a partir do PostgreSQL
SELECT * FROM mysql_products WHERE price > 100;
Otimização de Desempenho
1. Usar Pushdown de Cláusula WHERE
O PostgreSQL envia filtros para o servidor remoto:
-- Bom: Filtro aplicado remotamente
SELECT * FROM remote_users WHERE country = 'US';
-- Verificar plano de consulta
EXPLAIN (VERBOSE) SELECT * FROM remote_users WHERE country = 'US';
-- Procure por: "Remote SQL: SELECT ... WHERE country = 'US'"
2. Limitar Transferência de Dados
-- Ruim: Busca todas as colunas
SELECT * FROM remote_large_table;
-- Bom: Apenas colunas necessárias
SELECT id, username FROM remote_large_table;
-- Bom: Usar LIMIT
SELECT * FROM remote_large_table LIMIT 1000;
3. Otimizar Tamanho de Busca
-- Para conjuntos de resultados grandes
ALTER SERVER remote_db OPTIONS (SET fetch_size '50000');
-- Para consultas pequenas e frequentes
ALTER SERVER remote_db OPTIONS (SET fetch_size '1000');
4. Usar Estimativas Remotas
ALTER SERVER remote_db OPTIONS (ADD use_remote_estimate 'true');
-- O PostgreSQL consultará EXPLAIN remoto para estimativas de custo precisas
5. Índices em Tabelas Remotas
-- Garantir que as tabelas remotas tenham índices apropriados
-- Conectar diretamente ao banco de dados remoto:
CREATE INDEX idx_users_country ON users(country);
CREATE INDEX idx_orders_created_at ON orders(created_at);
6. Visões Materializadas para Dados Frequentemente Acessados
-- Armazenar em cache dados remotos localmente
CREATE MATERIALIZED VIEW cached_remote_data AS
SELECT * FROM remote_users WHERE active = true;
-- Atualizar periodicamente
REFRESH MATERIALIZED VIEW cached_remote_data;
-- Atualização automática com pg_cron se essa extensão estiver instalada
CREATE EXTENSION pg_cron;
SELECT cron.schedule('refresh-cache', '0 */6 * * *',
'REFRESH MATERIALIZED VIEW cached_remote_data');
Monitoramento e Solução de Problemas
Visualizar Servidores Remotos
SELECT
srvname AS server_name,
srvoptions AS options
FROM pg_foreign_server;
Visualizar Tabelas Estrangeiras
SELECT
foreign_table_schema,
foreign_table_name,
foreign_server_name
FROM information_schema.foreign_tables;
Verificar Mapeamentos de Usuário
SELECT
um.umuser::regrole AS local_user,
fs.srvname AS foreign_server,
um.umoptions AS options
FROM pg_user_mapping um
JOIN pg_foreign_server fs ON um.umserver = fs.oid;
Analisar Desempenho de Consulta
EXPLAIN (ANALYZE, VERBOSE, BUFFERS)
SELECT * FROM remote_users WHERE created_at > NOW() - INTERVAL '1 day';
Verificação de Conexão
Use EXPLAIN (ANALYZE, VERBOSE) para confirmar SQL remoto e tempo. Para links PostgreSQL-para-PostgreSQL, verifique também o pg_stat_activity do servidor remoto enquanto uma consulta FDW longa está em execução.
Problemas Comuns e Soluções
Problema 1: Tempo Limite de Conexão
Erro: could not connect to server
Soluções:
-- Adicionar tempo limite de conexão
ALTER SERVER remote_db OPTIONS (ADD connect_timeout '10');
-- Verificar conectividade de rede
-- Do shell:
psql -h remote-db.example.com -U user -d dbname
Problema 2: Consultas Lentas
Soluções:
-- Habilitar estimativas remotas
ALTER SERVER remote_db OPTIONS (ADD use_remote_estimate 'true');
-- Aumentar tamanho de busca
ALTER SERVER remote_db OPTIONS (SET fetch_size '100000');
-- Verificar se a cláusula WHERE foi enviada
EXPLAIN VERBOSE SELECT * FROM remote_table WHERE id > 1000;
Problema 3: Falha de Autenticação
Erro: password authentication failed
Soluções:
-- Atualizar mapeamento de usuário
ALTER USER MAPPING FOR postgres
SERVER remote_db
OPTIONS (SET password 'new_password');
-- Verificar pg_hba.conf no servidor remoto
-- Garantir que permite conexões do servidor local
Problema 4: Incompatibilidade de Tipo de Coluna
Erro: column type mismatch
Solução:
-- Converter colunas explicitamente
CREATE FOREIGN TABLE remote_data (
id INTEGER,
data TEXT,
created_at TIMESTAMP
)
SERVER remote_db
OPTIONS (table_name 'source_table');
-- Ou importar com tipos corretos
DROP FOREIGN TABLE remote_data;
IMPORT FOREIGN SCHEMA public
LIMIT TO (source_table)
FROM SERVER remote_db INTO public;
Considerações de Segurança
1. Usar Contas Somente Leitura
-- No banco de dados remoto, criar usuário limitado
CREATE ROLE fdw_readonly;
GRANT CONNECT ON DATABASE production_db TO fdw_readonly;
GRANT USAGE ON SCHEMA public TO fdw_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO fdw_readonly;
-- Usar no mapeamento de usuário
CREATE USER MAPPING FOR PUBLIC
SERVER remote_db
OPTIONS (user 'fdw_readonly', password 'safe_pass');
2. Armazenamento Seguro de Senhas
-- Você pode usar um arquivo .pgpass para conexões libpq em vez de armazenar
-- a senha no mapeamento de usuário. Confirme a propriedade e permissões do arquivo.
-- Formato ~/.pgpass:
-- hostname:port:database:username:password
CREATE USER MAPPING FOR postgres
SERVER remote_db
OPTIONS (user 'remote_user');
-- Senha lida do .pgpass
3. Segurança de Rede
-- Usar conexões SSL
-- No postgresql.conf do remoto:
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
-- Exigir SSL no mapeamento de usuário
CREATE SERVER secure_remote
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'remote.example.com',
dbname 'mydb',
sslmode 'require'
);
Melhores Práticas
- Minimizar transferência de dados: Selecione apenas colunas necessárias
- Usar índices: Garantir que tabelas remotas estejam devidamente indexadas
- Armazenar em cache dados frequentemente acessados: Usar visões materializadas
- Monitorar desempenho: EXPLAIN ANALYZE regular
- Limitar operações de escrita: Preferir somente leitura para a maioria dos usos de FDW
- Usar pool de conexões: Habilitar
keep_connections - Definir fetch_size apropriado: Ajustar com base nos padrões de consulta
- Testar cenários de failover: Planejar para indisponibilidade de banco remoto
- Documentar dependências externas: Manter documentação clara
- Auditorias de segurança regulares: Revisar mapeamentos de usuário e permissões
Conclusão
Os Foreign Data Wrappers do PostgreSQL são úteis para federação de bancos de dados, especialmente quando você precisa:
- Integração perfeita: Consultar dados remotos com SQL padrão
- Acesso em tempo real: Sem duplicação de dados ou atrasos de sincronização
- Suporte multi-banco: PostgreSQL, MySQL, Oracle e mais
- Desempenho: Pushdown de consulta quando o wrapper e a consulta suportam
- Flexibilidade: Acesso de leitura primeiro, com escritas somente após verificar o comportamento do wrapper
Comece com consultas somente leitura para bancos de dados remotos, otimize o desempenho com indexação adequada e tamanhos de busca, depois expanda para integrações mais complexas conforme necessário.