Clique no banner para conhecer e adquirir o meu treinamento de Bancos de Dados no Azure

SQL Server – Change Tracking vs CDC: Quando e como implementar rastreamento de dados leve

Post Views 19 views
This entry is part 22 of 22 in the series Security and Auditing
Reading time 11 minutes

Hey guys!

O assunto de hoje é sobre o pouco utilizado Change Tracking, um rastreamento de dados leve para identificar quais linhas de uma tabela foram inseridas/alteradas, muito útil para cargas incrementais, por exemplo.

Uma das sugestões mais comuns é utilizar Triggers, mas como vocês sabem, Triggers em tabelas grandes podem gerar muitos problemas de performance e um aumento drástico de LCK_M_IX e WRITELOG.

Outra opção é o CDC, mas o overhead de leitura do Log e o armazenamento das tabelas de “shadow” podem aumentar muito o consumo de disco.

É nesse cenário que o Change Tracking (CT) pode ser muito útil para conseguir rastrear todas as mudanças com um impacto quase imperceptível no Throughput da aplicação.

O que é o Change Tracking (CT)?

O Change Tracking é uma solução leve, projetada especificamente para cenários de sincronização unidirecional ou bidirecional. Ao contrário do CDC, que captura o “antes” e o “depois” de cada coluna, o CT apenas marca que uma linha foi alterada. Ele responde a pergunta: “Quais registros mudaram desde a minha última verificação?”.

Diferente de outras soluções, o Change Tracking não altera a estrutura das suas tabelas e não cria triggers. Ele trabalha de forma integrada ao motor do SQL Server. Quando você habilita o CT, o SQL passa a registrar as mudanças de DML (INSERT, UPDATE, DELETE) em uma estrutura interna.

O grande segredo aqui é o que ele armazena: apenas metadados da mudança e os valores da Primary Key das linhas alteradas. Se você atualizou uma coluna de descrição, o CT grava apenas que “a PK X mudou na versão Y”. Para pegar o dado novo, sua aplicação fará um JOIN da tabela de rastreio com a tabela original.

Observation: O Change Tracking rastreia toda e qualquer operação DML, mesmo que o valor final da coluna seja idêntico ao original (o famoso “update dummy”). Como o Change Tracking não armazena o histórico de valores antigos, apenas registra a Primary Key da linha alterada e o tipo da operação (Insert, Update ou Delete), se você precisa de auditoria completa com valores anteriores, a solução correta seria Temporal Tables ou CDC.

Quando usar Change Tracking?

  • Sincronização de Dados para Cache: Se você precisa atualizar um Redis ou ElasticSearch apenas com o que mudou no SQL.
  • ETL Incremental: Para alimentar um Data Warehouse sem precisar ler tabelas gigantescas via “Full Load” ou depender de colunas de Data_Atualizacao, que muitas vezes não possuem índice ou tecnicamente não é possível implementar essa coluna, como no caso de sistemas de terceiros. Além de conseguir tratar o problema de como tratar registros apagados.
  • Aplicações Mobile Offline: Onde o dispositivo precisa baixar apenas o “delta” de alterações desde a última sincronização.

Change Tracking vs. CDC vs. Temporal Tables

É fundamental entender onde o Change Tracking se posiciona no ecossistema do SQL Server:

Recurso Mecanismo Armazena Valor Antigo? Histórico Completo Overhead de Log Storage Extra Ideal para Pode perder histórico? Consumo incremental Impacto
Change Tracking Síncrono (Commit) No No Mínimo Muito baixo Sync / Lakehouse / Replicação Sim (janela de retenção) Watermark (CHANGETABLE) Baixíssimo
CDC Assíncrono (Log Reader) Yes Yes Alto Alto Auditoria / Replay / Compliance No LSN Alto
Temporal Tables Síncrono (Versionamento) Yes Yes Médio Muito alto Histórico funcional / SCD2 No Tempo (ValidFrom / ValidTo) Médio

Vantagens do Change Tracking

  • Baixo Overhead Transacional: Diferente do CDC, ele não lê o log de transação de forma assíncrona; a marcação é feita no commit da transação de forma muito otimizada.
  • Simplicidade de Consumo: A função CHANGETABLE facilita absurdamente a vida do desenvolvedor que precisa apenas do Delta.
  • Limpeza Automática: O AUTO_CLEANUP gerencia o purge dos dados antigos sem necessidade de Jobs complexos de manutenção.

Desvantagens do Change Tracking

  • Falta de Histórico: Se um registro foi alterado 10 vezes entre duas consultas suas, o CT dirá apenas que ele mudou. Você perde os estados intermediários.
  • Exigência de Primary Key: Se você tem tabelas legadas sem PK (um erro clássico de modelagem), esqueça o CT nelas.
  • Custo de Escrita: Embora leve, existe uma escrita síncrona adicional. Em ambientes com altíssima pressão de escrita, cada milissegundo conta.

Como saber se o Change Tracking está ativo?

Para saber se o Change Tracking está ativo, podemos consultar os metadados do sistema para validar tanto o banco de dados quanto as tabelas específicas:

Como ativar o Change Tracking no Banco de Dados

Para utilizar o recurso, primeiro habilitamos em nível de database. Aqui definimos o período de retenção (por quanto tempo o SQL manterá o histórico de mudanças) e se a limpeza automática (Auto Cleanup) estará ativa.

Important: Nunca defina uma retenção de Change Tracking muito alta (ex: 30 dias) em tabelas com milhões de updates diários. Isso fará com que a tabela interna cresça muito, afetando a performance de leitura do próprio CT e pode aumentar IO/Log, impactar cleanup, e degradar a consulta do CHANGETABLE e o throughput geral
Alerta Crítico: Ao desabilitar o Change Tracking no banco de dados, todas as estruturas internas de rastreamento são removidas imediatamente e todo o histórico de mudanças é definitivamente perdido. Não existe “Undo”. Ao reativar o recurso, será necessário habilitar o CT tabela por tabela novamente e iniciar uma nova carga completa (full load) para restabelecer a consistência dos dados sincronizados.

Como ativar o Change Tracking nas Tabelas

Após habilitar no banco, precisamos definir quais tabelas serão monitoradas.

Se você quiser desativar o Change Tracking de todas as tabelas do banco atual e também desativar a nível de banco de dados, pode utilizar o script abaixo:

Important: Para habilitar o Change Tracking, a tabela obrigatoriamente deve possuir uma Primary Key definida. Sem PK, o SQL Server não tem como rastrear a identidade da linha alterada.

O Conceito de Marca d’Água (Watermark) com Change Tracking

No modelo tradicional, usamos uma data ou um ID sequencial como “marca d’água”. No Change Tracking, a nossa marca d’água é o número da versão do Change Tracking, que é incremental e global do banco de dados (não é um sequencial por tabela), que basicamente quer dizer algo como “até aqui eu já li tudo e posso esquecer o passado”.

Pense que o SQL mantém uma fita contínua de commits:

Cada número é um commit que alterou qualquer tabela com o Change Tracking ativado. Essa fita anda para frente sozinha, você não controla. O watermark é simplesmente o “onde eu parei de ler” e a tabela de controle não guarda dados, apenas o último número da fita que já foi lida com sucesso.

Quando você executa:
CHANGETABLE(CHANGES dbo.Stg_Vendas, 104)

Isso significa basicamente: “Me traga tudo o que aconteceu depois do commit 104 nessa tabela.”

O controle de watermark é importante, especialmente se for utilizar várias tabelas, porque se o watermark da tabela ficar para trás e sair dessa janela, o SQL apaga fisicamente esse pedaço da fita. Quando você solicitar os dados a partir da versão 104 e a fita começar em 108, o SQL não tem mais os commits 105–107, e você terá perda definitiva de dados, sendo necessário rodar uma carga completa (FULL).

Por isso que é importante executar o comando CHANGE_TRACKING_CURRENT_VERSION() somente depois de consumir todos os dados dessa tabela com sucesso.

O fluxo lógico de uma leitura incremental segue estes passos:

  1. Obter a última versão processada: Consultamos uma tabela de controle onde guardamos até que versão que já foi lida.
  2. Obter a versão atual do banco: Chamamos a função CHANGE_TRACKING_CURRENT_VERSION().
  3. Ler o Delta: Usamos a função CHANGETABLE passando a versão antiga para iniciar a leitura das alterações a partir daquela versão.
  4. Atualizar a tabela de controle: Salvamos a nova versão para a próxima execução.
Important: Antes de consumir os deltas, sempre valide se o seu watermark for menor que esse valor. Se isso acontecer, parte do histórico já foi apagado pela política de retenção e você deve executar uma carga completa da tabela antes de continuar.

Para verificar a menor versão válida do watermark da tabela, você pode utilizar o comando SELECT CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID(N’dbo.MinhaTabela’))

Mãos na Massa: Script de Exemplo Completo

Abaixo, um script estruturado seguindo as melhores práticas de nomenclatura e performance, simulando um ambiente de carga e extração incremental.

Criação da tabela de teste, tabela de controle de cargas e ativação do Change Tracking

Faz algumas alterações na tabela pra testar:

Agora vou fazer a leitura das alterações e atualizar a tabela de controle com a versão atual da tabela:

Você verá esse resultado:

Valores da coluna SYS_CHANGE_OPERATION:

  • I = Insert
  • U = Update
  • D = Delete

Observation: Você deve ter notado que a operação de UPDATE não apareceu nas alterações do Change Tracking. Isso aconteceu porque o Change Tracking não registra um histórico completo de todas as operações, retorna o resultado final por chave desde a última versão sincronizada. Por isso, se uma linha foi atualizada e depois excluída antes da leitura do CHANGETABLE, você verá apenas a operação D, pois o UPDATE intermediário não é necessário para aplicar a sincronização.

Vamos fazer mais algumas mudanças na tabela:

Lendo novamente as alterações com o mesmo script utilizado anteriormente, você verá esse resultado:

Como o UPDATE ainda é válido, e a linha não foi excluída, como aconteceu no primeiro exemplo, podemos visualizar o registro da alteração (UPDATE) nos logs do Change Tracking.

Análise de Performance e Internals

Quando o Change Tracking está ativo, o SQL Server utiliza uma tabela interna (internal table) para armazenar as informações de mudança. O commit de qualquer transação na tabela rastreada agora inclui uma escrita adicional nessa tabela interna.

Principais Wait Types Relacionados:

  • WRITELOG: Como o CT é síncrono, o custo da escrita da mudança deve ser contabilizado no log de transação. Se o seu disco de log já estiver saturado, o CT pode agravar a latência de escrita.
  • CHECKPOINT: O processo de cleanup do CT (que remove registros antigos conforme a retenção) é executado em background e pode gerar IO.

Monitorando o espaço em disco utilizado pelo Change Tracking

Para garantir que o Change Tracking não está se tornando um vilão e consumindo muito espaço em disco, utilize a query abaixo:

Change Tracking em Ambientes de Alta Disponibilidade (AG) e Replicação

Essa é uma dúvida muito comum. Como o CT se comporta quando temos Always On Availability Groups ou operações de Restore?

Always On (AG)

O Change Tracking é totalmente compatível com Always On. As tabelas internas de rastreamento são estruturas internas persistidas e replicadas via log e, portanto, os dados de mudança são replicados para os secundários via log de transação normalmente.

Dica de Ouro: O processo de AUTO_CLEANUP roda apenas no Primário.

Backup e Restore / Attach Database

Ao restaurar um banco de dados com CT ativo em outro servidor, o recurso permanece ativo. No entanto, se você restaurar um backup antigo, a versão de controle (CHANGE_TRACKING_CURRENT_VERSION) estará desatualizada em relação ao que sua aplicação de sincronização já processou, o que pode exigir um “Full Sync” inicial.

WITH CHANGE_TRACKING_CONTEXT

Uma feature pouco explorada é o WITH CHANGE_TRACKING_CONTEXT. Imagine que você tem um processo de integração que altera dados e você não quer que esse mesmo processo “re-processe” essas mudanças.

Você pode enviar um contexto:

Isso evita loops infinitos de sincronização onde o Sistema A envia para o B, que devolve para o A. Vale lembrar que o contexto é gravado no commit, se o seu pipeline fizer múltiplas operações na mesma transação, todas herdam o mesmo contexto.

Limitações Técnicas

Antes de implementar, especialmente em produção, você precisa conhecer as limitações do Change Tracking:

  • Alteração de Primary Key: O Change Tracking não permite atualizar diretamente o valor de uma PK. Na prática, um UPDATE em uma coluna que faz parte da chave primária é tratado internamente como um DELETE da chave antiga seguido de um INSERT da nova chave, e o CT refletirá esse comportamento.
  • TRUNCATE TABLE: O comando TRUNCATE TABLE não gera eventos de Change Tracking. Se você truncar a tabela, o CT não registrará os deletes individuais e exigirá uma carga completa dessa tabela.
  • Colunas de Large Object (LOB): O CT não rastreia quais colunas LOB (VARCHAR(MAX), VARBINARY(MAX)) foram alteradas, então mesmo com TRACK_COLUMNS_UPDATED = ON, o Change Tracking não inclui colunas LOB no bitmap de colunas alteradas (SYS_CHANGE_COLUMNS). Assim, você sabe que a linha foi alterada, mas não consegue identificar exatamente quais colunas LOB mudaram.
Destaque de Performance: O rastreamento de colunas (TRACK_COLUMNS_UPDATED) adiciona um custo extra de armazenamento e CPU. Só habilite se sua lógica de sincronização realmente precisar saber qual campo mudou para evitar updates desnecessários no destino.

Espero que tenham gostado desse artigo, um grande abraço e até a próxima!