Pular para o conteúdo

Incremental por marca d'água — não é CDC

Aula 4 de 1210 minOperarAtualizada em 2026-10-04

Vídeo em produção

A gravação desta aula está no lote de produção. O objetivo, o exercício e a documentação já valem. Duração-alvo: 10 min.

Objetivo: Configurar watermark + chave; validar identidade com o full

Selo de estado: Preview (teto atual do produto) · Curso ACD-220 — Pipelines e medalhão Bronze/Silver/Gold · Aula 4 de 12 · Atualizado em 2026-10-04.

Objetivo#

Ao final desta aula você vai configurar watermark + chave; validar identidade com o full — escolher a coluna-chave de controle, entender a janela que o destino apaga e provar que o incremental bate com a carga completa.

Vídeo#

Identificador no manifesto: acd-220-04-incremental-por-watermark · duração-alvo 10 min · tela do produto: /sources.

Roteiro de gravação (6 capítulos):

#Minutagem-alvoCapítuloTela do produto
10:00–0:50Abertura: título + selo. A frase da aula: marca d'água não é CDC, e a Bronze não faz upsert por chave de negócio./sources
20:50–3:20Etapa Carga → Append → Coluna-chave de controle: as sugestões "— data, ideal", o selo coluna particionada — ideal para Append, e a recusa da coluna numérica./sources
33:20–5:40As cinco exigências do contrato, desenhadas: marca lida, janela fechada [início, fim), janela apagada, DELETE + WRITE_APPEND, preservação fora do recorte./sources
45:40–7:30Sobreposição e margem de atraso: por que a janela recomeça antes da marca e termina antes de "agora"./sources
57:30–9:00O aviso nominal quando um recurso marcado como incremental não vai carregar de forma incremental; e a recusa que cai para full./sources
69:00–10:00Validar a identidade com o full no Console de dados; encerramento com o "faça você mesmo"./dados

Conteúdo#

Três palavras que não são sinônimos

KEYSET é como a extração pagina na origem (WHERE chave > @desde ORDER BY chave ASC, sem OFFSET). Upsert por chave é o vocabulário do refresh incremental de snapshot de painéis e marts — outro subsistema. A escrita na Bronze não faz nenhum dos dois: ela apaga a janela da coluna-chave e acrescenta as linhas extraídas. E CDC (ler o log de transações da origem) é Roadmap — não existe hoje.

A coluna-chave de controle

Na etapa Carga, escolher Append numa tabela de banco abre o campo Coluna-chave de controle. A lista sugere primeiro as colunas de data/timestamp — marcadas "— data, ideal" — e depois as colunas id / *_id. O texto de ajuda da tela diz o que ela é: "a coluna que indica o que é novo (data/timestamp ou id crescente). A cada execução trazemos só os registros com valor maior que o último já carregado." Quando a coluna escolhida também é a de partição ou está na clusterização, aparece o selo verde "coluna particionada — ideal para Append".

Duas recusas valem decorar:

  • Sem coluna-chave, Append de banco não avança. A etapa bloqueia com o motivo: a carga não saberia de onde continuar.
  • Coluna numérica não serve para a escrita. A janela do destino compara coluna >= TIMESTAMP(@inicio) AND coluna < TIMESTAMP(@fim). Um id sequencial serve para paginar na origem, mas a carga não saberia apagar o recorte — e acrescentar sem apagar duplica. Um tipo que não diz tempo no nome é classificado como desconhecido e também recusado: nunca se assume tempo por otimismo.

As cinco exigências do contrato

Uma carga só pode ser chamada de incremental quando cumpre, nesta ordem:

#ExigênciaPor que ela existe
1Marca d'água persistida e LIDA como ponto de partida da próxima execuçãoUma marca apenas observada não é incremental: sem leitura, a próxima carga recomeça do começo
2Janela fechada [início, fim) — início inclusivo, fim exclusivoSem fim fechado, a linha que chega durante a extração cairia em duas janelas
3Deduplicação pela janela: o recorte é apagado no destino antes de acrescentarReler a mesma linha duas vezes não pode virar duas linhas
4Escrita = DELETE da janela + LOAD WRITE_APPENDÉ o que torna a reexecução idempotente dentro da janela
5Preservação fora do recorte: linha fora de [início, fim) não é lida, apagada nem reescritaÉ isso que separa incremental de recarga

Sobreposição e margem: os dois detalhes que parecem detalhe

Sobreposição (padrão 300 s): a janela recomeça um pouco antes da marca anterior. Uma origem transacional grava a linha com o horário do início da transação e só a torna visível no commit — uma linha de 10:00:00 pode aparecer às 10:00:07. Sem sobreposição ela sumiria para sempre; com sobreposição ela é relida, e o DELETE da janela impede a duplicata. É a sobreposição que transforma "append" em recuperação automática.

Margem de atraso (padrão 60 s): o fim da janela não é "agora", é agora − margem. Ler até agora pegaria uma janela ainda aberta na origem, e a marca avançaria por cima de linhas que ainda vão chegar.

E a marca avança para o fim da janela, não para o maior valor observado — exceto quando a extração foi truncada pelo teto de linhas. Nesse caso a janela do destino encolhe junto (fim = maior observado): apagar [início, fim) e recarregar só até o maior observado apagaria dado que não foi substituído, o pior defeito possível numa carga.

Quando o produto recusa e faz o full

A regra que sustenta o modo: o resultado incremental tem de ser idêntico ao refresh completo. Na menor dúvida, o produto recusa o incremental e faz o full, com motivo legível. Motivos típicos: adaptador sem semântica incremental implementada; tipo de ingestão não é append; coluna-chave ausente; tipo da coluna-chave não é de tempo; sem marca d'água anterior (a primeira execução é semeadura); extração sem recorte seguro.

Há ainda uma distinção que a tela faz questão de manter: semântica implementada (o motor existe e tem prova) é diferente de ativa no executor (algum executor realmente pede o plano). Quando um recurso está marcado como Append mas a carga que roda hoje ainda substitui a tabela, a etapa Carga diz isso com nome e motivo: "N recursos marcados como incrementais NÃO vão carregar de forma incremental". Leia esse bloco antes de prometer "incremental" a alguém — é a tela dizendo a verdade sobre o executor, não um aviso decorativo.

Deleção: a limitação assumida

Marca d'água não vê deleção. A linha apagada na origem continua no destino, porque a deleção não aparece na coluna-chave. Para restaurar a exatidão sob deleção: re-busque partições/dias inteiros por período, ou faça um full periódico. Um dado cuja origem apaga linhas não deve usar marca d'água pura.

Anti-injeção

Nomes de coluna (chave e cursor) são validados como identificadores simples antes de entrar no SQL; o valor da marca entra por parâmetro nomeado por engine ($1 no PostgreSQL, @since no SQL Server e BigQuery, ? no MySQL, :since no Oracle), nunca concatenado. Literal de cursor tem teto de 64 caracteres e recusa aspas, barra e quebra de linha — fora disso, faz full.

Exemplo: a Comércio Aurora

vendas tem atualizado_em (timestamp) e id (inteiro). Maria escolhe atualizado_em como coluna-chave — id é recusado para a escrita. A primeira execução é semeadura (não há marca anterior). A segunda roda com janela [marca − 5 min, agora − 1 min): apaga esse recorte em aurora_bronze.vendas e acrescenta as linhas extraídas. Uma venda registrada às 23:59:58 e commitada às 00:00:04 entra na janela seguinte pela sobreposição, sem duplicar. Para provar a identidade, Maria roda um full numa cópia de conferência e compara a contagem e a soma de valor por dia: os números batem.

Erros comuns

SintomaCausa provávelO que fazer
Sempre cai no fullSem marca anterior, ou coluna-chave inválidaA 1ª carga é semeadura; escolha uma coluna de tempo real
Não consigo avançar da etapa CargaAppend de banco sem coluna-chaveEscolha a coluna ou volte para Full
Escolhi id e a tela recusouA janela do destino é de tempoUse atualizado_em (ou outra data/timestamp)
Marquei Append e a tabela é substituídaSemântica não ativa no executor para aquele adaptadorLeia o aviso nominal com o motivo na etapa Carga
Faltam linhas apagadas na origemMarca d'água não vê deleçãoReprocessamento por período ou full periódico
Números não batem com o fullColuna-chave sem monotonia real na origemTroque a coluna; valide a identidade antes de confiar

O que é Preview aqui

O plano de carga, a elegibilidade, a idempotência dentro da janela e a identidade "incremental == full" são provados por teste determinístico (C07.1 = GA-candidato). A idempotência no destino depende de o BigQuery executar o DELETE da janela + LOAD WRITE_APPEND; isso não foi exercitado contra a nuvem nesta fase, e a tela mostra isso em vez de afirmar idempotência verificada. Custo faturado e latência de nuvem permanecem não medidos.

Faça você mesmo#

No workspace de treino Aurora Varejo, em vendas, com dados sintéticos.

  1. Em /sources, abra o pipeline de vendas e vá à etapa Carga. Troque vendas para Append.
  2. No campo Coluna-chave de controle, abra a lista e observe quais colunas vêm marcadas "— data, ideal". Tente escolher uma coluna id numérica e leia o motivo da recusa.
  3. Escolha atualizado_em. Se ela também for a coluna de partição, confirme que aparece o selo "coluna particionada — ideal para Append".
  4. Leia o cartão "Escrita no destino — efeito real" e copie para suas notas a frase sobre marca d'água e a frase sobre histórico fora da janela.
  5. Leia o bloco de aviso (se existir) sobre recursos marcados como incrementais que não vão carregar de forma incremental — anote o motivo que ele dá para o seu conector.
  6. Publique e rode duas execuções seguidas. Na segunda, confirme nos contadores que a Bronze recebeu menos linhas que na primeira.
  7. Valide a identidade: compare a contagem de linhas e a soma de valor por dia entre a tabela carregada incrementalmente e uma carga full de conferência, no Console de dados.
  8. Reexecute a mesma janela e confirme que a contagem não mudou — a janela é apagada antes de acrescentar.

Você terminou quando vendas está em Append com atualizado_em, a segunda execução leu menos que a primeira, a reexecução da mesma janela não duplicou nada, e os números batem com a carga completa de conferência — ou você sabe dizer qual condição fez o produto recusar o incremental.

Checagem rápida#

Três perguntas no final da aula, corrigidas no servidor. A aula só conta como concluída depois da checagem.

Documentação relacionada#

Capacidades ensinadas#

C07.1 — o selo exibido na aula é sempre o estado mais conservador entre as capacidades citadas; nada aqui é "GA".

Carregando seu progresso…