Buscar K
Aparência
Aparência
A carga Incremental tem um buraco que ela nunca resolveu sozinha: ela nunca apaga.
Se um pedido é excluído no ERP, nenhuma consulta incremental vai trazê-lo. Ele simplesmente deixa de aparecer na origem, e a linha correspondente fica no Data Warehouse para sempre, entrando em todo total, toda média e todo dashboard. Até hoje a única saída era uma carga Total, que reprocessa a origem inteira só para descobrir o que sumiu.
A sincronização de exclusões fecha esse buraco. Você informa uma consulta que devolve apenas as chaves que ainda existem na origem, e o Horus marca como excluído tudo que não veio.
IMPORTANT
A sincronização de exclusões existe apenas para dataflows de carga Incremental (load_type: Incremental). Ela não se aplica a carga Total nem a carga Temporal, e o produto recusa a configuração nesses dois casos.
O motivo é que ali ela não teria função: Total e Temporal apagam o destino antes de inserir, a primeira por inteiro e a segunda dentro da janela. Nas duas, um registro apagado na origem já desaparece do Data Warehouse sozinho, sem varredura nenhuma.
Ela complementa a carga Incremental e não substitui tipo de carga nenhum: roda como uma operação própria, agendada à parte da carga.
Cada tipo de carga responde de um jeito quando um registro é apagado na origem:
| Tipo de carga | Registro apagado na origem |
|---|---|
| Total | Some do Data Warehouse na execução seguinte. A tabela é esvaziada e recarregada. |
| Temporal | Some, desde que ele caia dentro da janela recarregada. Fora dela, permanece. |
| Incremental | Permanece para sempre. Nenhum delta contém aquilo que não existe mais. |
Não é uma limitação que dê para contornar escrevendo uma consulta melhor. Um registro apagado não aparece em delta nenhum, por definição: nenhum filtro na origem alcança o que não está mais lá.
A sincronização inverte a pergunta. Em vez de perguntar à origem o que mudou, ela pergunta o que ainda existe:
Nessa execução o dataflow não roda. Nenhum nó do fluxo é executado, nenhuma transformação acontece e nenhuma coluna de dado trafega. Só as chaves saem da origem, e é isso que torna a operação barata o bastante para rodar toda noite numa tabela grande.
A linha marcada some das consultas sozinha. Ela deixa de aparecer em dashboards, em totais e em qualquer leitura da tabela, sem que você precise filtrar nada nos relatórios.
Isso a diferencia da alternativa de exclusão lógica na origem (uma coluna de status ou data de exclusão trazida pela carga), em que a linha continua visível e todo relatório precisa lembrar de filtrá-la.
Este é o ponto que mais importa nesta página.
CAUTION
A consulta de chaves precisa devolver todas as chaves que uma carga Total traria, sem filtro de período, sem TOP, sem LIMIT e sem recorte de nenhum tipo. Tudo que não vier na consulta é marcado como excluído.
O engano natural é escrever a consulta de chaves com a mesma cabeça da consulta de extração, que é janelada por hábito:
-- ERRADO: apaga todo o histórico anterior a 30 dias
SELECT id FROM pedidos WHERE data_emissao >= CURRENT_DATE - 30-- Certo: o conjunto vivo inteiro
SELECT id FROM pedidosA consulta errada roda perfeitamente. Não há erro, não há aviso, e a execução termina com status de sucesso. Os pedidos com mais de 30 dias simplesmente desaparecem dos dashboards, e o problema costuma aparecer dias depois, num total histórico que não fecha.
O único sinal está no número que o log informa: uma varredura que marcou dezenas de milhares de linhas logo na primeira execução não encontrou uma limpeza na origem, encontrou um recorte na sua consulta. Veja Uma recusa aparece como execução bem-sucedida.
Vale entender por quê, porque a intuição aqui engana.
A carga Incremental descobre onde parou consultando o próprio Data Warehouse. Depois de uma varredura janelada, as linhas dos últimos 30 dias continuam vivas, então esse ponto de corte segue recente e a carga seguinte não relê nada de antigo. O histórico marcado continua marcado, e a única saída é rodar uma carga Total.
Se a consulta for restritiva o bastante para zerar a tabela, aí o produto recusa antes de marcar (veja O que o produto recusa). O caso perigoso é justamente o intermediário, em que parte do conjunto vem e parte não.
TIP
Antes de agendar, rode a consulta de chaves e a consulta de extração da carga Total lado a lado e compare a contagem de linhas. Os dois números precisam bater.
O produto recusa a configuração se qualquer um destes não valer:
| Exigência | Por quê |
|---|---|
load_type: Incremental no dataflow | Carga Total e Temporal apagam o destino antes de inserir, então a exclusão na origem já é refletida sem varredura. |
Tabela de destino com chave única (key_type: unique com key_columns) | A marcação de exclusão substitui a linha viva pela chave. Sem chave única não existe substituição, e a marcação só acrescentaria uma linha morta ao lado da viva. |
| Tabela de destino do tipo tabela, não do tipo nuvem | Tabela do tipo nuvem não vive no banco analítico e não tem chave. Nesse tipo, o controle do diferencial está nas opções do próprio nó Inserir Datawarehouse. |
| Tabela de destino identificável | A operação apaga registros. Sem saber onde, o produto recusa em vez de adivinhar. |
| Agente 1.27.0 ou mais novo | Quem executa a varredura é o agente. Num agente anterior a configuração pode ser salva e o agendamento pode ser criado, mas a execução não acontece. |
TIP
Confira a versão do agente em Agentes, antes de agendar. Agentes em Linux e em Docker se atualizam sozinhos ao reiniciar; os instalados via MSI no Windows têm o botão Atualizar Agente no painel. Veja Agentes.
No editor do dataflow, com a carga Incremental escolhida e a tabela de destino com chave única, ative Sincronizar exclusões e informe:
IMPORTANT
Use uma credencial somente leitura nesta consulta. Ela não precisa de mais nada além de leitura, e a validação que exige SELECT olha o texto da consulta, o que não alcança toda função com efeito colateral. A credencial restrita é a defesa que vale.
A consulta precisa devolver as colunas de chave e nada além delas. Colunas a mais ou a menos são recusadas antes de qualquer marcação acontecer.
Isso não é preciosismo de formato. Se a chave fosse lida com uma conversão diferente da que a carga normal usa, ela não encontraria seu par no destino, e uma linha viva seria marcada como excluída sem erro nenhum.
O casamento é por nome de coluna, não por posição:
ID, tanto SELECT id quanto SELECT ID servem.PEDIDO_ID alimentada por uma coluna id da origem, escreva SELECT id AS PEDIDO_ID.Nome que não bate é recusado antes de qualquer marcação, com a lista do que faltou e do que sobrou.
O botão de teste faz mais do que rodar a consulta. Ele compara as colunas devolvidas com a chave da tabela de destino e diz qual está faltando e qual está sobrando.
Uma consulta que roda perfeitamente devolvendo a coluna errada é exatamente o engano cujo estrago só apareceria de madrugada, no destino. Por isso o teste não se contenta em responder "funcionou".
A sincronização roda por agendamento, no contexto Sincronizar exclusões. A opção aparece na lista de contextos apenas para dataflows que têm a consulta de chaves configurada.
O desenho comum separa as duas rotinas por frequência:
| Rotina | Contexto | Frequência típica |
|---|---|---|
| Carga do dado | Incremental | Alta: a cada 10 minutos, a cada hora |
| Sincronização de exclusões | Sincronizar exclusões | Baixa: uma vez por noite |
A carga incremental é o que mantém o dado atual; a varredura é o que mantém o dado honesto. Exclusão raramente precisa ser refletida em minutos, e a varredura lê o conjunto de chaves inteiro toda vez, então rodá-la de hora em hora cobra da origem sem entregar quase nada.
NOTE
Um mesmo dataflow não executa duas vezes ao mesmo tempo. Se a carga estiver rodando quando a varredura for disparada, ela espera a carga terminar.
A varredura apaga por ausência, e isso a separa de toda outra carga: aqui uma falha de leitura e o resultado "não existe mais" chegam iguais. Conexão caindo, permissão revogada ou tabela renomeada devolvem zero linha, do mesmo jeito que uma origem realmente vazia.
Por isso existem duas recusas:
A consulta não devolveu chave nenhuma. Seguir marcaria a tabela inteira como excluída. O produto para antes e registra o motivo.
A contagem não fecha (mais linhas a marcar do que linhas existentes no destino). Isso indica defeito, não decisão, então não há o que confirmar.
WARNING
Não existe recusa por proporção. Uma varredura que marca 90% da tabela passa, desde que a consulta tenha devolvido alguma chave. Não há um teto do tipo "recuse se for apagar mais que X%", porque esse número não existe de forma honesta: uma tabela de log pode expurgar 30% por noite e um cadastro nunca perde 1%.
A conferência de que a consulta devolve o conjunto certo é sua, antes de agendar.
Se a origem esvaziou de propósito e você quer mesmo zerar o destino, o caminho é rodar uma carga Total, que apaga o destino antes de inserir.
WARNING
Quando o guarda recusa, a execução termina com status de sucesso, e não de erro. O guarda funcionando é uma proteção, não uma falha, então nada é reportado como quebra.
Isso significa que o status verde não confirma que a varredura marcou alguma coisa. Quem distingue é o texto do log de execução.
Abra a execução e leia a última linha do log:
| O que o log diz | O que aconteceu |
|---|---|
12 de 48.320 linhas marcadas como excluídas. | A varredura rodou e marcou. |
0 de 48.320 linhas marcadas como excluídas. | A varredura rodou e nada sumiu na origem. É o resultado esperado na maioria das noites. |
Varredura recusada: <motivo> | A varredura não fez nada. O motivo está na própria mensagem. |
O contador de linhas da execução não ajuda aqui: ele fica zerado em toda varredura, inclusive nas que marcaram linhas. O número que vale é o da mensagem.
TIP
Confira essa linha nas primeiras noites depois de configurar, que é quando uma consulta de chaves mal escrita ainda custa barato. Uma consulta com recorte se denuncia por um número alto logo na primeira execução; uma consulta que quebrou se denuncia pela recusa.
O caso mais comum, e o que este recurso existe para resolver. Os valores abaixo são um ponto de partida razoável: ajuste a frequência ao seu volume, mas mantenha a proporção entre as duas rotinas.
1. A tabela de destino
| Propriedade | Valor |
|---|---|
key_type | unique |
key_columns | [PEDIDO_ID] |
2. O dataflow
| Propriedade | Valor |
|---|---|
load_type | Incremental |
load_type_column | ATUALIZADO_EM |
Consulta de extração, como já seria sem a sincronização:
SELECT id AS PEDIDO_ID, status, valor, atualizado_em AS ATUALIZADO_EM
FROM pedidos
WHERE atualizado_em > '{LastDataPoint}'3. A consulta de chaves
Credencial: uma somente leitura da mesma origem.
SELECT id AS PEDIDO_ID FROM pedidosRepare no que ela não tem: nenhum WHERE, nenhum LIMIT, nenhuma junção. Ela devolve o conjunto vivo inteiro, e a única coluna é a chave do destino, com o alias que faz o nome bater.
4. Os dois agendamentos
| Agendamento | Contexto | Gatilho | Janela |
|---|---|---|---|
Pedidos Incremental | Incremental | A cada 1 hora | 06:00 às 22:00 |
Pedidos Sincronizar exclusões | Sincronizar exclusões | Uma vez por dia, 03:00 | (dia inteiro) |
Ambos com timezone: America/Sao_Paulo. Inclusão e alteração chegam de hora em hora pela carga incremental; exclusão chega na varredura da madrugada.
As 03:00 são uma escolha deliberada: fora do horário comercial, depois de as cargas noturnas terem terminado, e com folga até as 06:00 para uma varredura demorada não atrasar a primeira carga do dia.
Quando a chave do destino tem mais de uma coluna, a consulta devolve todas elas, com os mesmos nomes. A ordem não importa.
Destino com key_columns: [PEDIDO_ID, PRODUTO_ID]:
SELECT pedido_id AS PEDIDO_ID, produto_id AS PRODUTO_ID
FROM pedido_itensO item removido de um pedido que continua existindo some do Data Warehouse, porque a chave daquele item deixou de vir.
A varredura lê o conjunto de chaves inteiro toda vez que roda. O custo dela não acompanha quanto mudou, e sim quantas linhas a tabela tem.
| Situação | Frequência sugerida |
|---|---|
| Cadastro ou tabela até alguns milhões de linhas | Uma vez por dia, de madrugada |
| Tabela grande, exclusão rara | Uma vez por dia, ou nos dias úteis apenas |
| Exclusão precisa aparecer no mesmo dia | Duas vezes por dia, por exemplo 03:00 e 13:00 |
Rodar de hora em hora raramente compensa: paga-se a leitura completa das chaves toda vez para refletir uma exclusão algumas horas mais cedo. Se o requisito for exclusão em minutos, a conversa é sobre exclusão lógica na origem, e não sobre frequência de varredura.
Seja qual for a frequência escolhida, confira o resultado no log das primeiras execuções: veja Uma recusa aparece como execução bem-sucedida.
A varredura não substitui a carga Total em toda situação. Prefira Total quando:
load_type apaga antes de inserirkey_type e key_columns no Data Warehouse