Output PostgreSQL
Aplica as mensagens em tabelas de um PostgreSQL, mantendo a tabela de destino igual à tabela de origem: inserções, atualizações e exclusões acontecem no destino conforme chegam. É o Output usado para réplica operacional — ter os dados de um sistema disponíveis em outro banco, atualizados em segundos.
Duas fases
O trabalho acontece em duas fases, automaticamente, e a virada de uma para a outra não exige nada de você:
- Carga inicial — o conteúdo atual das tabelas é gravado de uma vez, depois de a tabela de destino ser esvaziada.
- Fluxo contínuo — a partir daí, só as mudanças trafegam: inserções, atualizações e exclusões.
Pré-requisitos no PostgreSQL
- As tabelas de destino já devem existir, com as colunas correspondentes.
- Cada tabela precisa de índice único sobre as colunas declaradas como chave. Sem isso a atualização não tem como funcionar, e o node falha ao subir.
- Um usuário com leitura, escrita e
TRUNCATEnessas tabelas.
O que este Output precisa ler
Diferente da maioria dos Outputs, este exige um formato específico de mensagem:
| Parte | Como é usada |
|---|---|
| Headers | op diz o que fazer; schema e table dizem de qual tabela de origem a linha veio. Os três são obrigatórios — sem eles a mensagem é recusada. |
| Value | A linha em JSON plano. Usado quando op é r, c ou u. |
| Key | As colunas da chave em JSON. Usada quando op é d. |
op | O que o Output faz |
|---|---|
r | Insere a linha (carga inicial) |
c | Insere a linha |
u | Atualiza a linha correspondente à chave |
d | Apaga a linha correspondente à chave |
O Input SQL Server CDC produz exatamente esse formato. Qualquer outro
Input precisa de um Transform que monte os headers op, schema e
table.
Exemplo — inserção ou atualização
Key: {"ID":42}
Value: {"ID":42,"CLIENTE":"ACME","TOTAL":249.90,"ATUALIZADO_EM":"2026-07-26T11:02:31Z"}
Headers: op=u schema=dbo table=pedidos
A linha de ID=42 na tabela de destino fica com os valores novos. Se ela não existisse, seria
inserida.
Exemplo — exclusão
Key: {"ID":42}
Value: (vazio)
Headers: op=d schema=dbo table=pedidos
A linha ID=42 é apagada. Repare que o Value vem vazio — a identificação da linha está na Key.
Campos
Conexão
| Campo | O que é | Padrão |
|---|---|---|
| Host | Endereço do servidor PostgreSQL. | — |
| Porta | Porta de conexão. | 5432 |
| Database | Banco de destino. | — |
| Usuário | Usuário de acesso. | — |
| Senha (secret) | O Secret com a senha. | — |
| SSL Mode | Como a conexão é cifrada, do mais seguro para o menos: verify-full, verify-ca, require, prefer, allow, disable. | require |
| Schema padrão | Schema usado quando a tabela de destino é informada sem schema. | public |
Mapeamento de tabelas
Cada tabela de origem precisa de uma linha no mapeamento apontando para a tabela de destino:
| Campo | O que é |
|---|---|
| Schema de origem | O schema como vem no header schema da mensagem — ex.: dbo. |
| Tabela de origem | A tabela como vem no header table — ex.: orders. |
| Chave primária | Colunas que identificam a linha, separadas por vírgula. São elas que o Output usa para decidir entre inserir e atualizar. As colunas precisam ter índice único no destino — isso é conferido quando o node sobe. |
| Tabela de destino | Onde gravar, no formato schema.tabela ou só a tabela (usando o schema padrão). Duas origens não podem apontar para o mesmo destino — cada uma tem seu próprio controle de carga inicial, e a segunda apagaria o que a primeira carregou. |
Numa chave composta, o campo Chave primária recebe as colunas separadas por vírgula — ex.:
PEDIDO_ID, ITEM_ID para uma mensagem cuja Key é {"PEDIDO_ID":1234,"ITEM_ID":3}.
Lote e desempenho
O Output acumula linhas antes de gravar, e o lote fecha pelo que vier primeiro:
| Campo | O que é | Padrão |
|---|---|---|
| Linhas por lote | Quantas linhas são acumuladas antes de uma gravação. | 10000 |
| Segundos por lote (flush) | Tempo máximo de espera antes de enviar um lote incompleto. | 10 |
| Timeout de query (segundos) | Tempo máximo de uma gravação antes de ser abortada. | 300 |
| Conexões máximas | Quantas conexões simultâneas com o banco. | 4 |
O lote inteiro viaja como um único parâmetro da consulta, então aumentar demais custa memória. Por isso o padrão é bem menor que o do Snowflake, onde há um custo por gravação a amortizar.
Recomeçar do zero
| Campo | O que é |
|---|---|
| Sufixo do Group ID | A parte do marcador de leitura que você controla. O nome base é gerado a partir da pipeline e do node e não pode ser alterado. Permitido: letras, números, hífen e underline. |
Trocar o sufixo e publicar de novo é o único botão de recomeçar que existe. O Output esquece até onde tinha lido, relê o tópico desde o começo, esvazia a tabela de destino e refaz a carga completa.
Apagar a tabela no braço não recomeça nada — o controle de "já carreguei esta tabela" fica do lado da plataforma, não do banco.
Cuidados de operação
Rode uma cópia só. Duas cópias no mesmo grupo de consumo podem esvaziar a tabela uma da outra durante a carga inicial.
A validação acontece na subida. O Output confere as tabelas e colunas mapeadas quando o node sobe. Um mapeamento errado falha na hora, com a mensagem do que está errado — e não silenciosamente na primeira leva de dados.
A confirmação de leitura acontece depois da gravação, então um node que morre entre uma coisa e outra reenvia aquele lote ao voltar. Aqui isso não duplica nada: a inserção da carga inicial ignora linhas cuja chave já está no destino. (O Snowflake não tem essa proteção.) O preço é que uma chave repetida dentro da própria origem entra uma vez só, sem aviso.
Detalhes que evitam surpresa
- Só as colunas que chegam são gravadas. Uma coluna que existe no destino mas não vem na
mensagem é deixada em paz: o
DEFAULTdela vale na inserção e o valor atual sobrevive à atualização. É o que permite manter colunas de auditoria no destino. - O nome da coluna é comparado sem diferenciar maiúsculas de minúsculas. Um campo
ORIGEMna mensagem grava na colunaorigemdo destino. (O Snowflake é o oposto: lá a grafia precisa bater exatamente.) - Campos que o destino não tem são descartados em silêncio. Se você adiciona um campo novo num Transform, crie a coluna correspondente antes.
- Colunas geradas nunca são escritas; colunas de identidade recebem o valor da origem, para a chave original ser preservada.