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#
- Uma fonte conectada com pelo menos uma carga full já feita (o snapshot base).
- Uma coluna de watermark: crescente, sem buracos para trás. Boas escolhas:
atualizado_em(timestamp) ou umidsequencial.
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 doOFFSET). 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#
- Garanta uma carga full inicial da fonte/tabela (o snapshot base).
- 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). - Salve e rode o refresh. O Ingestia busca só o delta (
> marca) e faz upsert. - 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:
Modo: incremental
Coluna de watermark: atualizado_em
Chave de upsert: idConsulta de delta que o Ingestia monta (PostgreSQL, conceitual):
SELECT * FROM "public"."pedidos"
WHERE "atualizado_em" > $1 -- $1 = última marca d'água
ORDER BY "atualizado_em" ASC
LIMIT 5000; -- um fragmentoA 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
nulle 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#
| Sintoma | Causa provável | O que fazer |
|---|---|---|
| Sempre cai no full | sem snapshot anterior, ou sem cursor válido | Faça a 1ª carga full; escolha uma coluna crescente real |
| Faltam linhas apagadas na origem | watermark não vê deleção | Use período/partições completas/tombstones ou full |
| Números não batem com o full | ordenação/chave incorretas | Garanta ORDER BY = chave ASC; revise a chave de upsert |
| Cursor recusado | valor > 64 chars ou com aspas | Use 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.