Quando a base deixa de ser brinquedo e passa a atualizar todo dia, aparece uma pergunta inevitavel: vou reprocessar tudo ou atualizar so o que mudou?
E ai entra o UPSERT.
A promessa e boa: inserir novos registros e atualizar os antigos sem recriar a tabela inteira. O problema e que muita gente tenta aplicar esse padrao cedo demais, sem chave confiavel e sem staging organizada. O resultado costuma ser duplicidade, historico estranho e desconfiança sobre a base final.
O que um UPSERT deveria fazer
A ideia de um UPSERT e simples:
- se a chave ainda nao existe, insere;
- se a chave ja existe, atualiza.
No papel, parece trivial. Na pratica, ele so e seguro quando tres coisas estao claras:
- qual e a chave do registro;
- qual versao deve vencer em caso de conflito;
- qual e a regra para registros apagados, atrasados ou corrigidos.
Sem isso, voce nao tem carga incremental. Tem loteria incremental.
O erro classico: confiar na origem crua
Um erro comum e aplicar MERGE direto sobre uma tabela de origem que ja chega com duplicidade, atraso ou linha corrigida.
Se a staging contem duas versoes do mesmo pedido, por exemplo, o banco pode atualizar duas vezes, falhar por conflito ou consolidar algo que voce nem queria manter.
Antes do UPSERT, limpe a staging.
Um padrao minimo costuma incluir:
- deduplicar pela chave de negocio;
- usar uma coluna de recencia, como
updated_at; - manter so a linha mais recente por chave antes da escrita final.
Um modelo mental simples
Pense em tres camadas:
- bruta: recebe a origem como ela vem;
- staging tratada: organiza, padroniza e deduplica;
- tabela final: recebe o
UPSERT.
Esse desenho e importante porque separa ingestao de decisao. A base bruta guarda a verdade operacional. A staging decide o que e valido para escrita. A tabela final serve o consumo analitico.
Quando tudo acontece em uma etapa so, fica mais dificil debugar.
Exemplo de raciocinio
Imagine uma tabela de pedidos cuja chave e pedido_id.
Voce recebe um lote diario com:
- pedidos novos;
- pedidos antigos com status alterado;
- alguns registros repetidos pela API.
O fluxo minimo seria:
- carregar o lote bruto;
- deduplicar por
pedido_id, mantendo oupdated_atmais recente; - aplicar
MERGEna tabela final.
Em SQL, a ideia fica parecida com isto:
MERGE INTO pedidos_final AS destino
USING staging_pedidos AS origem
ON destino.pedido_id = origem.pedido_id
WHEN MATCHED THEN
UPDATE SET
status = origem.status,
valor = origem.valor,
updated_at = origem.updated_at
WHEN NOT MATCHED THEN
INSERT (pedido_id, status, valor, updated_at)
VALUES (origem.pedido_id, origem.status, origem.valor, origem.updated_at);
O MERGE e so a ponta visivel. O que protege de verdade e a qualidade da origem.
Nao esqueça dos apagados
Nem toda fonte manda um “delete” explicito. As vezes um registro some. As vezes muda de status. As vezes vira inativo.
Por isso, o UPSERT sozinho nao cobre todos os cenarios.
Voce precisa decidir:
- registro ausente no lote significa exclusao?
- significa atraso de ingestao?
- significa que o lote e parcial?
Essa resposta muda a logica de carga e a leitura de negocio. O pior erro aqui e assumir sem validar com quem conhece a origem.
Validacao pos-carga nao e opcional
Depois do UPSERT, sempre confira pelo menos:
- quantidade de chaves unicas na tabela final;
- duplicidade por chave;
- quantos registros foram inseridos;
- quantos foram atualizados;
- se alguma metrica de controle saiu do intervalo esperado.
Se a base final passou a ter mais de uma linha por chave, sua logica de incremental falhou.
Quando nao vale insistir
Existe um ponto pragmatico importante: nem toda base precisa de UPSERT.
Se o volume e pequeno, a janela e curta e o reprocessamento completo custa pouco, talvez uma carga full refresh ainda seja melhor. Menos elegante, mas mais robusta.
O erro e adotar incremental so porque parece mais avancado.
Resumo direto
UPSERT bom nao comeca no MERGE. Ele comeca na definicao da chave, na limpeza da staging e na regra de recencia.
Se voce quer um padrao minimo seguro, lembre desta sequencia:
origem bruta -> staging deduplicada -> UPSERT -> validacao pos-carga
Isso ja evita boa parte das duplicidades que fazem times perderem horas desconfiando da tabela final.
