Três versões da mesma linha de cadastro em uma tabela, com janelas de vigência diferentes

Alguém corrige o cadastro de um cliente numa segunda de manhã. Muda a cidade, muda o segmento, salva e vai tomar café. Ninguém comenta o assunto.

Na sexta, o gerente comercial abre o relatório de vendas por região do ano passado e vê um número diferente do que viu em janeiro. Nenhum pipeline falhou. Nenhuma execução deu erro. Nada foi apagado por engano.

O problema é que a tabela de origem não guarda o que era verdade antes. Ela guarda o que é verdade agora. E o seu pipeline copiou isso fielmente, por cima do passado.

Neste artigo, explicamos o que cada modo de sincronização faz com a tabela de destino e o que é SCD tipo 2 em termos de linha e de coluna. Também mostramos o que ele custa e como escolher tabela a tabela.

O que o espelhamento faz — e o que ele apaga junto

Espelhar é manter no destino uma cópia fiel do estado atual da origem. Linha nova entra, linha alterada é atualizada, linha que sumiu é removida. Ao fim de cada execução, origem e destino contam a mesma coisa.

Para a maior parte das tabelas isso é exatamente o que você quer. Um pedido cancelado deve sumir do destino. Um endereço corrigido deve aparecer corrigido. Ninguém abre o painel de estoque querendo saber quantas unidades havia em julho.

O que o espelhamento de banco de dados não faz é guardar o que estava ali antes. Ele não tem onde. Cada linha do destino tem lugar para uma versão só, e a versão que fica é sempre a última. Na prática, o seu relatório histórico é reescrito toda madrugada, em silêncio.

O destino é uma foto do presente.

SCD tipo 2 é linha nova, não atualização

Slowly changing dimension (dimensão que muda lentamente) é o nome que Ralph Kimball deu, em 1996, ao problema de um atributo descritivo mudar com o tempo. Cliente muda de cidade, produto muda de categoria, vendedor muda de região. São mudanças raras, e é justamente por serem raras que ninguém percebe o estrago.

O tipo 2 resolve de um jeito só: nada é atualizado. Toda mudança gera uma linha nova, e a linha antiga é fechada com uma data de fim. A tabela passa a ter várias linhas por entidade, cada uma válida num intervalo de tempo.

Um cliente que mudou de cidade e depois de faixa de fidelidade fica assim:

versão id_cliente cidade faixa válido de válido até ativa
8801 4471 São Paulo Bronze 10/01/2024 15/03/2025 não
9142 4471 Belo Horizonte Bronze 15/03/2025 02/02/2026 não
9905 4471 Belo Horizonte Prata 02/02/2026 em aberto sim

Repare que o fim de uma versão é exatamente o início da seguinte. O intervalo é fechado no começo e aberto no fim, então não sobra buraco entre as linhas e nenhuma data cai em duas versões ao mesmo tempo.

Três coisas mudam de lugar. O id_cliente deixa de identificar a linha e passa a identificar a entidade, repetido em todas as versões. Quem identifica a linha é o par chave mais início de vigência — ou uma coluna de versão criada pela carga, quando a implementação gera uma. E a tabela de vendas passa a apontar para a versão, não para o cliente.

A venda de fevereiro de 2025 aponta para a versão de São Paulo. Ela continua sendo uma venda de São Paulo depois da mudança de cidade, depois da promoção de faixa, depois de tudo. É isso que o tipo 2 compra: o passado para de andar.

As implementações variam, o mecanismo é um só

Você vai encontrar o tipo 2 implementado de várias formas. O conceito é um só; o que varia é o conjunto de colunas de controle.

  • Só marcador de versão ativa: barato e limitado. Você sabe qual versão vale hoje e não sabe quando cada uma valeu. Não responde "como estava em 15 de março".
  • Só janela de vigência: mais expressivo. Exige comparar datas em toda consulta.
  • Vigência mais marcador: o arranjo mais comum. A redundância é de propósito, porque filtrar pela versão ativa é bem mais barato que comparar duas datas.
  • Número de versão ou chave substituta: uma coluna própria por linha, útil para a tabela de fatos apontar direto para a versão e para auditar a carga.
  • Fim em aberto: nulo ou uma data-sentinela como 31/12/9999. A sentinela dispensa tratar nulo em toda comparação de data; o nulo é mais honesto sobre o que ainda não aconteceu. Quem guarda também o marcador de versão ativa raramente sente a diferença.
  • Detecção por comparação ou por assinatura: a carga compara coluna a coluna, ou guarda uma assinatura das colunas monitoradas e compara só ela. Em tabela larga, a assinatura é mais rápida.
  • Colunas monitoradas e não monitoradas: nem toda mudança merece versão. Telefone digitado errado é correção, não mudança de negócio.

Nomes diferentes, mesma ideia: fechar em vez de sobrescrever.

Os outros tipos, em uma frase cada

O tipo 2 é o mais usado, não o único. Kimball formalizou os demais na terceira edição do The Data Warehouse Toolkit, em 2013.

  • Tipo 0: o valor original nunca muda. Data de cadastro, canal de origem, CPF.
  • Tipo 1: sobrescrita pura. O SCD tipo 1 é o espelhamento, e serve para corrigir erro.
  • Tipo 2: linha nova por versão, com vigência.
  • Tipo 3: uma coluna a mais guarda o valor anterior. Guarda um passo de histórico, não todos.
  • Tipo 4: o histórico sai da tabela principal e vai para uma tabela separada.
  • Tipo 5: tipo 4 com um atalho para o perfil atual na tabela principal.
  • Tipo 6: linha versionada que também carrega o valor atual, para responder às duas perguntas.
  • Tipo 7: a tabela de fatos guarda duas chaves, e a consulta escolhe se quer o passado ou o agora.

Do 4 em diante, a motivação é quase sempre a mesma: o tipo 2 cresceu demais.

O que o tipo 2 custa

Ele resolve um problema real e cria três.

A tabela cresce. Uma dimensão com atributo volátil e alguns milhões de linhas vira um problema de armazenamento e de consulta. Vale medir antes de ligar o modo em tudo.

A junção errada duplica tudo. Se alguém juntar a tabela de vendas à de clientes só pelo id_cliente, cada venda vira três. É o erro mais comum de quem acabou de ligar o tipo 2, e ele não dá erro: dá número inflado com cara de certo.

Toda consulta de "agora" precisa de filtro. O painel que antes era um SELECT direto passa a exigir o filtro da versão ativa. Quem esquecer, soma o cliente três vezes.

As três consultas abaixo mostram a diferença. A primeira é a que infla o número:

sql · a junção certa depende da pergunta

-- errado: cada venda vira uma linha por versão do cliente
SELECT c.cidade, SUM(v.valor)
  FROM vendas v
  JOIN clientes c ON c.id_cliente = v.id_cliente
 GROUP BY c.cidade;

-- "como estava na época": a data da venda escolhe a versão
SELECT c.cidade, SUM(v.valor)
  FROM vendas v
  JOIN clientes c ON c.id_cliente = v.id_cliente
                 AND v.data_venda >= c.valido_de
                 AND (v.data_venda < c.valido_ate OR c.valido_ate IS NULL)
 GROUP BY c.cidade;

-- "como está hoje": filtra a versão ativa
SELECT c.cidade, SUM(v.valor)
  FROM vendas v
  JOIN clientes c ON c.id_cliente = v.id_cliente
                 AND c.ativa
 GROUP BY c.cidade;

São perguntas diferentes, com respostas diferentes e legítimas. O tipo 2 não escolhe por você — ele apenas torna as duas possíveis.

Exemplo prático

Uma rede de varejo reorganiza o mix e move 400 produtos de categoria em janeiro. Com espelhamento, comparar o faturamento por categoria com o do ano passado fica sem sentido: o ano passado é recalculado com a categoria de hoje. Com tipo 2, os dois anos continuam comparáveis, e dá para medir o que a mudança de mix fez com a margem. É a mesma tabela, com decisões opostas.

Como decidir, tabela a tabela

A decisão não é da conexão nem do pipeline. É de cada tabela, e às vezes de cada coluna.

Vale o tipo 2 quando o atributo entra em relatório histórico, quando alguém compara períodos por ele, ou quando existe obrigação de mostrar o que valia numa data. Cadastro de cliente, tabela de produtos, hierarquia comercial, tabela de preços.

Fique no espelhamento quando o passado do atributo não interessa a ninguém, quando a tabela é grande e volátil, ou quando o dado já é um evento com data própria. Pedido, movimentação de estoque, log de acesso.

Não existe modo melhor ou pior. Existe o modo que a pergunta do seu time exige — e a maior parte dos destinos acaba com tabelas nos dois.

Como isso aparece no Januss

No Januss o modo é escolhido tabela a tabela, dentro da mesma origem. Uma tabela em carga completa, outra em espelhamento, outra em histórico, no mesmo pipeline. O modo histórico é o SCD tipo 2.

Quando a tabela é marcada como histórico, o Januss cria o destino com quatro colunas de controle além das suas:

sql · colunas de controle do modo histórico

_januss_valid_from  TIMESTAMP  NOT NULL   -- início da vigência
_januss_valid_to    TIMESTAMP  NULL       -- nulo enquanto a versão está aberta
_januss_active      BOOLEAN    NOT NULL   -- a versão ativa da chave
_januss_synced_at   TIMESTAMP  NOT NULL   -- quando esta linha foi escrita

A chave primária da tabela de destino passa a ser a sua chave mais o _januss_valid_from — é o par que identifica a versão, exatamente como na seção acima. Os nomes são os padrões: se _januss_ não combina com a convenção do seu destino, os cinco nomes de coluna de sistema são definidos na sua conta e valem para todos os pipelines.

Na carga seguinte, o motor compara a versão ativa com a linha que chegou da origem. Igual, não escreve nada — reentrega de mensagem não gera versão duplicada. Diferente, fecha a versão ativa e insere a nova na mesma transação: o _januss_valid_to da linha fechada recebe o mesmo instante do _januss_valid_from da nova. O encadeamento vem do commit, não da sorte do relógio.

Linha que some da origem também não é apagada. A versão ativa é fechada e a entidade fica sem versão aberta — o passado dela continua consultável.

Duas limitações que vale conhecer antes de ligar o modo. A comparação é sobre todas as suas colunas: não dá para escolher quais delas disparam versão nova, então o telefone digitado errado gera uma versão como qualquer outra mudança. E quando o mesmo registro muda várias vezes dentro do mesmo lote de captura, o Januss guarda a imagem final do lote, não cada passo intermediário. A fidelidade é por execução, não por evento.

Quer ver com o seu dado qual modo cada tabela pede? São 14 dias de teste, sem cartão de crédito: criar seu workspace.

Fontes

Os tipos de slowly changing dimension e a nomenclatura seguem o Kimball Group:

Crie seu workspace em minutos.

Escolha o modo por tabela e veja o histórico se formar no seu destino, com vigência e versão ativa.

Criar workspace 14 dias · sem cartão de crédito