Skip to content

This page has not been translated yet — you are reading the Portuguese version. View in Portuguese

GA candidateUpdated on 2026-09-08

Tutorial — criar um pipeline incremental por watermark

Passo a passo para configurar carga incremental por marca d'água (watermark), trazendo só o delta com garantia de bater com o full.

On this page (15)

Estado: Preview. A identidade "incremental == full" é provada por teste determinístico (esta capacidade = GA-candidato); a execução real no datalake e o custo faturado = NÃO MEDIDO. Exemplos sintéticos.

Leia antes: Modos de carga · Referência: incremental e backfill.


O que é#

A carga incremental por watermark traz só as linhas novas desde a última execução, usando uma coluna crescente (uma data de atualização ou um id) como marca d'água. É muito mais barata que o full e, por construção, produz o mesmo resultado.

Isto não é CDC. É comparação por marca d'água (coluna > última marca). CDC de verdade (INSERT/UPDATE/DELETE do log da fonte) é Roadmap — não existe hoje.

Para que serve#

Manter fresca uma tabela grande que cresce/atualiza (pedidos, eventos, lançamentos) sem reler o histórico inteiro a cada refresh.

Quando usar / quando não usar#

  • Use quando: há uma coluna crescente e confiável (ex.: atualizado_em, id) e as linhas antigas não somem da origem.
  • Não use quando: a fonte apaga linhas sem sinal de deleção — use o modo por período (re-busca dias inteiros) ou um full. Veja "Deleção" abaixo.

Plano e permissões#

  • Núcleo · verificação de acesso · chaves de desligamento para execução de ingestão, atualização de painéis, consultas no console de dados.

Pré-requisitos#

  1. Uma fonte conectada com pelo menos uma carga full já feita (o snapshot base).
  2. Uma coluna de watermark: crescente, sem buracos para trás. Boas escolhas: atualizado_em (timestamp) ou um id sequencial.

Como funciona por dentro#

  • Pull de banco / BigQuery: paginação KEYSET (seek) — WHERE wm > <última marca> ORDER BY wm ASC, avançando a marca para o maior valor do último lote. Estável mesmo se a fonte mudar durante a extração (ao contrário do OFFSET). O valor da marca entra por parâmetro nomeado por engine (Postgres $1, SQL Server/BigQuery @since, MySQL ?, Oracle :since), nunca concatenado.
  • Refresh de widget/mart: guarda a marca d'água do snapshot anterior e faz UPSERT por chave com o delta; o histórico é reaproveitado. O predicado é >= de propósito (re-busca a linha exatamente na marca; o upsert é idempotente e não perde a fronteira).

Passo a passo#

  1. Garanta uma carga full inicial da fonte/tabela (o snapshot base).
  2. Na configuração da fonte/tabela (ou do widget de série temporal), ative o modo incremental e informe a coluna de watermark (ex.: atualizado_em).
  3. Salve e rode o refresh. O Ingestia busca só o delta (> marca) e faz upsert.
  4. Valide a identidade: rode um refresh incremental e um refresh completo e confirme que os números batem. Se não puder bater com segurança, o produto recusa o incremental e faz o full (com o motivo no log) — isso é esperado.

Exemplo (sintético)#

Tabela pedidos com id e atualizado_em:

code
Modo: incremental
Coluna de watermark: atualizado_em
Chave de upsert: id

Consulta de delta que o Ingestia monta (PostgreSQL, conceitual):

sql
SELECT * FROM "public"."pedidos"
WHERE "atualizado_em" > $1 -- $1 = última marca d'água
ORDER BY "atualizado_em" ASC
LIMIT 5000; -- um fragmento

A marca d'água avança para o maior atualizado_em do lote; o próximo fragmento continua de onde parou.

Resultado esperado#

  • Cada refresh lê muito menos dados (só o delta) e o resultado é idêntico ao full — mesmas linhas, mesma ordem.
  • Sem cursor utilizável no snapshot anterior, o Ingestia grava null e o próximo refresh cai no full (seguro).

Semântica de deleção (limitação assumida)#

O merge é UPSERT. Sem sinal de deleção, o incremental não remove uma chave que sumiu da origem (mesmo contrato de dbt/Power BI). Para restaurar a exatidão sob deleção:

  • use partições completas (re-busca a partição inteira e remove a chave ausente); ou
  • forneça tombstones (chaves deletadas explícitas); ou
  • use o modo por período (re-busca dias inteiros); ou
  • faça um full periódico.

Limites e custos#

  • Janela por período (quando aplicável): default 7 dias, teto 400.
  • Paginação: teto 10.000 páginas / 5.000.000 linhas.
  • Literal de cursor: ≤ 64 caracteres, sem aspas/barra/quebra.
  • O incremental existe para reduzir custo; o teto de bytes faturáveis protege sempre. Custo faturado em BRL = NÃO MEDIDO.

Segurança#

  • Nomes de coluna (chave/cursor) validados como identificadores simples antes do SQL.
  • Valor do cursor por bind (parâmetro nomeado); literal recusa aspas/barra/quebra.
  • Compat N−1: um leitor novo lê snapshot antigo (sem cursor) sem quebrar — e, diante dele, recusa o incremental e faz full.

Erros comuns#

SintomaCausa provávelO que fazer
Sempre cai no fullsem snapshot anterior, ou sem cursor válidoFaça a 1ª carga full; escolha uma coluna crescente real
Faltam linhas apagadas na origemwatermark não vê deleçãoUse período/partições completas/tombstones ou full
Números não batem com o fullordenação/chave incorretasGaranta ORDER BY = chave ASC; revise a chave de upsert
Cursor recusadovalor > 64 chars ou com aspasUse uma coluna de watermark simples (data/id)

Diagnóstico#

  • Compare lado a lado o resultado do refresh incremental e do full.
  • Leia o motivo no log quando o produto recorre ao full — ele diz exatamente qual condição de elegibilidade não foi satisfeita.

Relacionados#


Última revisão: 2026-09-08.

Related links