Skip to content

Tipos de carga ​

Toda carga responde duas perguntas, e o Dataflow só fica correto quando as duas estão certas.

A primeira é quanto se pede da origem. Trazer a tabela inteira do ERP toda madrugada custa caro no banco do cliente, então existe a opção de trazer só uma janela de datas ou só o que mudou desde a última execução. Essa é a Extração.

A segunda é o que fazer com o que chegou. O Data Warehouse já tem dados da carga anterior, e alguém precisa decidir se eles são substituídos, atualizados um a um pela chave, ou apenas acrescentados. Essa é a Gravação.

A escolha sai da natureza do dado na origem e de quantas vezes a carga vai rodar. Escolher errado não dá erro. A carga termina com sucesso e a tabela fica com linha duplicada ou faltando, e você descobre num total que não fecha, semanas depois.

Extração ​

ModoO que trazPrecisa de
Totala tabela inteira, a cada execuçãonada
Janelaum intervalo de datasuma coluna de data na origem
Incrementalsó o que mudou desde a última execuçãouma coluna que só cresce

A Total é a mais simples e a única sem risco de duplicar, porque o estado final depende só da última execução. Serve para dimensão e tabela de referência: cidade, categoria, plano de contas, cadastro de produto. O custo é reprocessar a origem inteira toda vez, o que inviabiliza tabela fato grande.

A Janela recorta por data. Você diz o período, por exemplo o mês passado, e o Agente ETL injeta {StartDate} e {EndDate} com as duas pontas dele para a consulta usar. É o modo padrão de fato grande, porque absorve correção retroativa na origem sem reprocessar histórico.

sql
SELECT * FROM vendas
WHERE DATA_EMISSAO BETWEEN '{StartDate}' AND '{EndDate}'

A Incremental busca o ponto de corte: o maior valor que a coluna de controle já atingiu no destino, injetado como {LastDataPoint}. Na primeira execução ele vem zerado e a carga traz tudo.

sql
SELECT * FROM pedidos
WHERE UPDATED_AT > '{LastDataPoint}'

IMPORTANT

A consulta precisa usar as variáveis no WHERE. Se o SQL não usar {StartDate} e {EndDate}, ou {LastDataPoint}, o Dataflow traz a base inteira e a Extração não recortou nada na origem, que era o único motivo de ela existir.

E se os dados não vierem de um SQL? As mesmas variáveis funcionam na URL e no corpo de um HTTP Request, e chegam ao Python como variável de verdade, sem chaves. Ver Variáveis.

TIP

A janela e o ponto de corte chegam prontos, e dá para calcular em cima deles. Um nó Configurador Python produz variáveis antes da carga começar: é assim que se recua o ponto de corte para pegar registro que a origem gravou fora de ordem, se monta a conexão na hora, ou se gera a consulta a partir de um de-para.

Gravação ​

ModoO que acontece com o que já estava no destino
Substituir tudoapaga tudo, depois insere o que chegou
Substituir a janelaapaga o que está dentro da janela, depois insere o que chegou
Atualizar por chavenão apaga nada, e sobrescreve a linha que tiver a mesma chave
Somente inserirnão apaga e não sobrescreve, tudo entra como linha nova

Substituir tudo e Substituir a janela apagam. Atualizar por chave e Somente inserir não apagam nunca. Essa diferença decide uma coisa só, e é a mais importante desta página: se um registro apagado na origem some ou não do Data Warehouse.

Substituir tudo ​

Apaga o que está no destino, depois insere o que a consulta trouxe. O estado final depende só da última execução, então essa é a Gravação que nunca duplica.

Ela reflete exclusão sozinha: o que foi apagado na origem não vem na consulta, e como o destino foi limpo antes, não volta.

Substituir a janela ​

Faz duas coisas, nessa ordem. Apaga a janela no destino, depois insere o que a consulta trouxe.

Essa ordem resolve a exclusão de graça, dentro da janela. Um pedido apagado no ERP não vem na consulta, e como a janela dele já foi apagada, ele não volta. Fora da janela, nada é percebido.

E é pela mesma ordem que dado some por engano. Para o Agente ETL, "esse pedido foi apagado no ERP" e "a consulta não trouxe esse pedido dessa vez" são a mesma situação, uma linha que não veio.

Por isso a consulta precisa devolver tudo que existe dentro da janela, e nada fora dela.

Se ela deixar de fora uma linha que estava na janela, a linha é apagada. Se ela devolver uma linha com data fora da janela, a linha entra, mas a cópia antiga continua lá, porque estava fora da janela que foi apagada. Ficam duas.

Ler mais do que a janela é outra coisa, e é permitido. Um cálculo pode precisar de cinco anos de venda para produzir uma linha de resumo do mês passado. O que a consulta lê é livre. O que ela devolve é que precisa caber na janela.

Atualizar por chave ​

Não apaga nada. A linha que chega toma o lugar da que já existia com a mesma chave, e uma carga que traz o mesmo pedido três vezes deixa uma linha só, a última.

Depende da tabela do HorusDW ter chave única definida. Sem ela, a linha repetida se acumula ao lado da antiga em vez de substituí-la.

Como nada é apagado, exclusão na origem não é percebida. Um pedido apagado no ERP continua no Data Warehouse indefinidamente. As duas saídas são uma carga Total periódica, ou a Sincronização de Exclusões quando a tabela for grande demais para isso.

WARNING

Se a consulta devolve um milhão de linhas e o destino fica com meio milhão, a chave está incompleta. Duas linhas diferentes que compartilham a mesma chave viram uma só, e a última carregada toma o lugar da anterior. O sintoma é o total bater no preview do Dataflow e não bater no dashboard. A chave precisa conter todas as colunas que distinguem uma linha da outra.

Somente inserir ​

Não apaga e não sobrescreve. Tudo que chega entra como linha nova.

Serve para log e telemetria, onde o registro nasce e nunca é atualizado. Em qualquer outro caso ele duplica, porque a segunda carga do mesmo registro vira uma segunda linha.

Exclusão na origem também não é percebida aqui, pelo mesmo motivo da Gravação anterior.

As combinações ​

ExtraçãoGravaçãoPré-condição
TotalSubstituir tudonenhuma
JanelaSubstituir a janelacoluna de janela imutável
JanelaAtualizar por chavedestino com chave única
IncrementalAtualizar por chavedestino com chave única
IncrementalSomente inserirorigem que nunca atualiza registro

Os pares que não aparecem na tela são os que duplicariam ou apagariam dado. Uma Extração Total com Somente inserir, por exemplo, empilharia a base inteira a cada execução.

Como escolher ​

A escolha não sai do tamanho da tabela nem da frequência da carga. Ela sai de como o dado está na origem, e três perguntas resolvem quase todo caso.

A origem tem uma data que nunca muda depois que o registro nasce? Data de emissão, data de venda, created_at. Se tem, e a tabela é grande, você quer Janela com Substituir a janela. Esse par recarrega o período pedido e traz de graça as correções e exclusões feitas nele.

A origem tem uma coluna que só cresce? Um updated_at que sobe a cada alteração, ou um ID sequencial. Se tem, você quer Incremental. Com updated_at a Gravação é Atualizar por chave, porque o mesmo registro vai voltar várias vezes ao longo da vida dele. Com ID sequencial de um log que nunca é alterado, Somente inserir basta.

A origem apaga registro de verdade? Se apaga, e você está em Incremental, nenhuma consulta vai trazer o que foi apagado, porque ele deixou de existir do lado de lá. Duas saídas: Sincronização de Exclusões, que compara as chaves vivas na origem contra o destino, ou uma carga Total periódica, quando a tabela couber nisso.

Não sobrou nenhuma dessas? Total. É o caso da tabela de cadastro que muda pouco e não tem coluna de controle nenhuma.

A frequência entra depois e raramente muda o par escolhido. Ela descarta o Total numa tabela grande que precisa rodar de minuto em minuto, e decide a largura das janelas quando o par é Janela. Ver Várias janelas no mesmo Dataflow.

WARNING

A coluna da janela precisa ser imutável. data_emissao e created_at servem. data_vencimento e data_alteracao não, porque o valor migra ao longo da vida do registro. Quando ele migra, a janela do destino deixa de corresponder à janela da origem, e a carga apaga uma linha que a consulta não vai devolver. Para data que muda, use Janela com Atualizar por chave, que não apaga nada.

Janela com Atualizar por chave ​

Esse par existe para o caso em que a data da origem não é imutável e mesmo assim você quer recortar por período.

Como ele não apaga a janela, a consulta fica livre do compromisso de espelhar exatamente o intervalo que seria apagado. Você pode filtrar por mais de uma data ao mesmo tempo, o que a Janela com Substituir a janela não permite:

sql
SELECT * FROM titulos
WHERE DATA_PAGAMENTO BETWEEN '{StartDate}' AND '{EndDate}'
   OR DATA_VENCIMENTO BETWEEN '{StartDate}' AND '{EndDate}'
   OR DATA_EMISSAO    BETWEEN '{StartDate}' AND '{EndDate}'

O título entra na carga se qualquer uma das três datas caiu no período, e a chave única resolve as repetições. É o modo certo para contas a pagar, contas a receber e título em geral, onde o registro fica interessante por motivos diferentes em momentos diferentes.

Em troca, como nenhuma Gravação que não apaga, ele não percebe exclusão na origem. Ver Atualizar por chave.

O lado da tabela ​

Metade do contrato mora na tabela do HorusDW, não no Dataflow. Abra a tabela em Editar Tabela e configure dois campos.

Tipo de Chave escolhe entre Chave Única e Chave Duplicada. Chave Única é o que habilita a Gravação Atualizar por chave, porque com ela o Data Warehouse garante que não existam duas linhas com a mesma chave. Chave Duplicada permite repetição, e é o que Somente inserir espera encontrar.

Colunas Chave é o conjunto de colunas que forma essa chave. Com Chave Única, são elas que determinam a unicidade de um registro. Com Chave Duplicada, elas viram a ordenação da tabela e servem para acelerar consulta.

Mudar qualquer um dos dois é alteração estrutural. Ao salvar, o HorusDW avisa que a tabela será reconstruída e os dados existentes serão perdidos. Eles voltam na próxima carga do Dataflow.

TIP

Numa Janela com Substituir a janela, prefira Chave Única mesmo sem precisar de sobrescrita. Se a substituição falhar por qualquer motivo, Chave Duplicada multiplica os registros e Chave Única os deduplica.

Pelo Lumo CLI os mesmos campos estão em Referência: table.

Exemplo ​

Um fato de vendas que recarrega o mês corrente todo dia, recortado pela data de emissão do pedido. A Extração é Janela sobre DATA_EMISSAO, e a Gravação é Substituir a janela.

A consulta recorta o mesmo intervalo que a Gravação vai substituir:

sql
SELECT p.id AS PEDIDO_ID, i.produto_id AS PRODUTO_ID,
       p.data_emissao AS DATA_EMISSAO, i.valor_item AS VALOR_ITEM
FROM pedidos p
JOIN pedido_itens i ON i.pedido_id = p.id
WHERE p.data_emissao BETWEEN '{StartDate}' AND '{EndDate}'

A tabela de destino declara PEDIDO_ID e PRODUTO_ID como chave única, o que a protege caso a substituição da janela falhe no meio.

A cada execução, o Agente ETL tira de fato_vendas as linhas cuja DATA_EMISSAO cai na janela pedida e insere as que o Dataflow trouxe. Fora da janela, o histórico não é tocado.

Para montar isso em YAML, pelo Lumo CLI, veja Referência: flow e Referência: table.

A janela na execução ​

A Extração define a regra e a janela concreta vem na hora de executar. Na execução manual você escolhe entre Total e quatro formas de Janela: dias passados, dias futuros, mês e ano, ou ano inteiro. Pela CLI o mesmo controle está em --context, e a lista de valores fica em Execução e Agendamento.

O contexto escolhe o intervalo da Extração e não altera a Gravação.

A primeira carga ​

Um Dataflow de Janela recém-criado tem o destino vazio, e uma janela de um mês traria só aquele mês. Para trazer o histórico, rode uma vez com contexto Total, que ignora a janela e busca a origem inteira. Depois disso o agendamento diário assume, recarregando só a janela.

Vale o mesmo para reprocessar um período antigo que chegou errado: um contexto de mês ou de ano recarrega aquele intervalo sem tocar no resto.

Na Extração Incremental não é preciso fazer nada. O ponto de corte começa zerado, então a primeira execução já traz tudo e as seguintes trazem só a novidade.

Várias janelas no mesmo Dataflow ​

Um Dataflow de Janela pode entrar em mais de um agendamento, cada um com uma largura e uma frequência. Quem faz isso ganha frescor e cobertura ao mesmo tempo, sem pagar a janela larga a cada rodada.

FrequênciaJanela
a cada 5 minutos1 dia
de hora em hora30 dias
a cada 6 horas90 dias
uma vez por noite, ou por semanaTotal

Os números acima são um exemplo, não uma receita. O que decide é a volumetria da tabela, quanto processamento você tem disponível, o quanto a origem aguenta ser consultada, e até quando atrás ela ainda recebe correção. Uma origem que nunca mexe em venda de mais de 15 dias não precisa da faixa de 90.

A Total no fim da escada não é redundância. A Janela só percebe exclusão que caia dentro dela, então é a Total periódica que fecha o que ficou para trás. Em tabela grande demais para isso, a saída é a Sincronização de Exclusões.

O custo de cada faixa está em Consumo de Processamento, e vale a conta antes de escolher os intervalos: em Janela, dobrar a frequência dobra os bytes gravados.

Cargas em camadas ​

Uma tabela do Data Warehouse pode ser a origem de outro Dataflow. É assim que se montam camadas: um fluxo traz vendas do ERP, outro lê vendas e produz cohort_clientes.

Não existe carga em várias etapas. Existe uma carga por etapa, cada uma com a sua Extração e a sua Gravação, e a segunda não sabe que a origem dela é uma tabela do próprio Data Warehouse em vez de um ERP. O {StartDate} do segundo fluxo é a janela dele, e o ponto de corte dele sai do destino dele. O nó de Lakehouse aceita as mesmas variáveis que um extrator de banco aceita.

O que muda são três cuidados.

A ordem importa. O fluxo derivado precisa rodar depois do que alimenta a origem dele, no mesmo agendamento. Fora de ordem, ele lê o que ainda não foi gravado e produz um resultado de ontem.

A janela não pode encolher camada a camada. Se vendas recarrega o mês corrente e cohort_clientes recarrega os últimos 7 dias, uma correção que entrou em vendas no dia 3 nunca chega ao cohort. Cada camada seguinte usa uma janela igual ou maior que a anterior.

Ler e produzir são coisas diferentes. Para responder se um cliente estava ativo numa data base, o cálculo precisa das vendas até aquela data, não só das vendas da janela. Então o filtro de leitura vira DATA_VENDA <= {EndDate} enquanto a Gravação continua substituindo só a janela de datas base. A Extração lê o que a conta precisa, e a Gravação recorta o que a conta produziu.

Na Extração Incremental o mesmo raciocínio vale, com um limite. O ponto de corte sai de uma coluna que só cresce no destino, e camada que agrega costuma não ter essa coluna. Quando não tiver, a camada derivada é Janela ou Total, mesmo que a de baixo seja Incremental.

Modos de falha ​

O que quebra na prática, e como perceber.

A tabela duplica. Você está em Incremental ou em Janela com Atualizar por chave, e o destino está com Chave Duplicada. Cada alteração do registro na origem virou uma linha nova. Conserte na tabela, trocando o Tipo de Chave para Chave Única.

O total bate no Dataflow e não bate no dashboard. A chave única está incompleta, e duas linhas diferentes que compartilham a mesma chave viram uma só. O preview do Dataflow mostra o que a consulta trouxe, e o dashboard mostra o que sobrou depois da chave. Acrescente à chave as colunas que distinguem uma linha da outra.

Registros somem sem ninguém ter apagado. Você está em Janela com Substituir a janela sobre uma coluna que muda, tipicamente data_alteracao ou data_vencimento. Troque a Gravação para Atualizar por chave, ou a coluna da janela para uma imutável.

Um total não fecha e ninguém acha o erro. Você está em Incremental e a origem apaga registro. O que foi apagado lá continua no Data Warehouse indefinidamente, entrando em todo dashboard. Ver Sincronização de Exclusões.

A carga demora o mesmo que antes de virar Janela. A consulta não usa {StartDate} e {EndDate}, então a origem devolve tudo e o recorte acontece tarde demais.

Uma carga Total não limpou o que você esperava. A Total substitui o que aquele Dataflow escreveu, e não a tabela inteira. Quando dois Dataflows alimentam a mesma tabela, cada um limpa a própria parte.

Relacionados ​