Change Tracking vs CDC: Qual o Melhor para Monitorar Mudanças no SQL Server?
Fala galera,
Espero que estejam todos bem! 😊
No post de hoje vou falar sobre um assunto que sempre gera dúvidas entre DBAs e Desenvolvedores. Quando usar Change Tracking e quando usar Change Data Capture (CDC) para monitorar alterações nos dados?
O objetivo desse post é esclarecer as diferenças entre Change Tracking e CDC, com exemplos práticos que vocês podem testar no seu ambiente.
Antes de mais nada, vamos entender o básico. Change Tracking é uma funcionalidade do SQL Server que foi introduzida na versão 2008. Ela permite que você identifique quais linhas foram modificadas em uma tabela, mas não armazena os valores que foram alterados.
Pense no Change Tracking como um “detector de mudanças” simples. Ele apenas te avisa: “Olha, a linha com PK=123 foi alterada”, mas não te diz o que mudou nem qual era o valor anterior. É uma tecnologia leve, que adiciona pouco overhead ao sistema, e ideal para cenários onde você só precisa saber se algo mudou, não necessariamente o que mudou.
Vamos ver um exemplo prático.
Primeiro, vamos criar nossa base de testes e criar uma tabela de Funcionários:
-- Habilitando Change Tracking no banco
ALTER DATABASE TesteChangeTracking
SET CHANGE_TRACKING=ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)
Use TesteChangeTracking
GO
-- Criando uma tabela de exemplo
CREATE TABLE Funcionarios (
ID INT IDENTITY(1,1) PRIMARY KEY,
Nome VARCHAR(100),
Salario DECIMAL(10,2),
Departamento VARCHAR(50),
DataContratacao DATE
)
Agora vamos habilitar o Change Tracking no banco, veja como é simples
-- Habilitando Change Tracking na tabela
ALTER TABLE Funcionarios
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = ON)
Agora vamos inserir alguns dados e depois fazer algumas alterações:
-- Inserindo dados de teste
INSERT INTO Funcionarios (Nome, Salario, Departamento, DataContratacao)
VALUES
('João Silva', 5000.00, 'TI', '2023-01-15'),
('Maria Santos', 6000.00, 'RH', '2022-08-20'),
('Pedro Oliveira', 4500.00, 'Financeiro', '2023-03-10')
-- IMPORTANTE: Capturar a versão ANTES das mudanças
DECLARE @versao_inicial BIGINT = CHANGE_TRACKING_CURRENT_VERSION()
PRINT 'Versão inicial: ' + CAST(@versao_inicial AS VARCHAR(20))
-- Fazendo algumas alterações
UPDATE Funcionarios SET Salario = 5500.00 WHERE ID = 1
DELETE FROM Funcionarios WHERE ID = 3
INSERT INTO Funcionarios (Nome, Salario, Departamento, DataContratacao)
VALUES ('Ana Costa', 5200.00, 'Marketing', '2023-11-01')
-- Agora vamos ver o que mudou (usando a versão capturada)
SELECT
CT.ID,
CT.SYS_CHANGE_VERSION,
CT.SYS_CHANGE_OPERATION,
F.Nome,
F.Salario,
F.Departamento
FROM CHANGETABLE(CHANGES Funcionarios, @versao_inicial) AS CT
LEFT JOIN Funcionarios F ON CT.ID = F.ID
Analisando o resultado acima : ID=1, OPERATION=’U’ (Update), ID=3, OPERATION=’D’ (Delete) e ID=4, OPERATION=’I’ (Insert).
Vejam que temos as operações, mas não sabemos qual era o salário anterior do João. Essa é a principal característica do Change Tracking, podemos ver que os dados mudaram, mas não conseguimos ver os dados anteriores a mudança.
Agora vamos falar do (CDC – Change Data Capture). O CDC é uma funcionalidade mais robusta, também introduzida no SQL Server 2008, mas nas edições Enterprise, Developer e Express (com limitações). O CDC não apenas detecta mudanças, mas também armazena os valores antes e depois da alteração. É como ter um “histórico completo” de todas as mudanças que aconteceram nos seus dados.
Porém, como tudo na vida, essa funcionalidade mais completa vem com um custo, maior consumo de espaço em disco, maior overhead no sistema e maior complexidade para gerenciar.
Vamos ver o CDC em ação:
Precisamos habilitar o CDC nas opções avançadas do SQL Server
-- Primeiro, habilitamos CDC no banco (requer sysadmin)
USE master
GO
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'Agent XPs', 1
RECONFIGUREAgora vamos habilitar o CDC na base de testes
USE TesteCDC
GO
-- Habilitando CDC no banco
EXEC sys.sp_cdc_enable_db
-- Criando nossa tabela de teste
CREATE TABLE Produtos (
ID INT IDENTITY(1,1) PRIMARY KEY,
Nome VARCHAR(100),
Preco DECIMAL(10,2),
Categoria VARCHAR(50),
Estoque INT,
DataUltimaAtualizacao DATETIME2 DEFAULT GETDATE()
)Vamos habilitar o CDC na tabela Produtos
-- Habilitando CDC na tabela
EXEC sys.sp_cdc_enable_table
@source_schema = 'dbo',
@source_name = 'Produtos',
@role_name = NULL,
@supports_net_changes = 1Observação Importante : Certifique-se que seu SQL Server Agent esteja ligado quando for fazer isso, pois o CDC cria Jobs para capturar os registros e para a limpeza.
Caso o seu SQL Server Agent não estiver Habilitado, você irá receber uma mensagem assim :


Confira se os serviços estão realmente ligados e refaça a operação se necessário.

Essa é a mensagem esperada

Agora vamos inserir dados e fazer alterações:
-- Inserindo dados de teste
INSERT INTO Produtos (Nome, Preco, Categoria, Estoque)
VALUES
('Notebook Dell', 2500.00, 'Informática', 10),
('Mouse Logitech', 50.00, 'Informática', 100),
('Cadeira Gamer', 800.00, 'Móveis', 5)
-- Fazendo alterações
UPDATE Produtos SET Preco = 2300.00, Estoque = 8 WHERE ID = 1
UPDATE Produtos SET Estoque = 95 WHERE ID = 2
DELETE FROM Produtos WHERE ID = 3
-- Consultando as mudanças no CDC
SELECT
__$operation,
CASE __$operation
WHEN 1 THEN 'Delete'
WHEN2THEN'Insert'
WHEN 3 THEN 'Update (antes)'
WHEN 4 THEN 'Update (depois)'
END AS Operacao,
__$start_lsn,
__$update_mask,
ID,
Nome,
Preco,
Categoria,
Estoque
FROM cdc.dbo_Produtos_CT
ORDER BY __$start_lsn
Veja a diferença. Com CDC temos acesso tanto aos valores antigos quanto aos novos. Para cada UPDATE, o CDC cria dois registros, um com os valores antes da alteração (operation=3) e outro com os valores depois (operation=4).
Maneiro, né?
Onde usar o Change Tracking e onde usar o CDC?
Agora que vimos as duas em ação, vou compartilhar exemplos de quando usar cada uma. O Change Tracking é ideal quando você precisa de sincronização de dados simples, ou seja, quando você só precisa saber quais registros mudaram para replicar para outro sistema. Também é a escolha certa quando o baixo overhead é fundamental, especialmente quando performance é crítica e você não pode abrir mão de velocidade. É muito útil para detecção de conflitos em cenários de sincronização bidirecional e em cenários de cache onde você precisa invalidar cache baseado em mudanças.
Exemplos de uso do Change Tracking
Sincronização com um BI onde você só precisa saber quais Funcionarios foram alterados para reprocessar os dados:
USE TesteChangeTracking
-- Criando tabela de funcionários
CREATE TABLE Funcionarios (
ID INT IDENTITY(1,1) PRIMARY KEY,
Nome VARCHAR(100),
Salario DECIMAL(10,2),
Departamento VARCHAR(50),
DataContratacao DATE
)
-- Habilitando Change Tracking na tabela
ALTER TABLE Funcionarios
ENABLECHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = ON)
-- Inserindo dados iniciais
INSERT INTO Funcionarios (Nome, Salario, Departamento, DataContratacao)
VALUES
('João Silva', 5000.00, 'TI', '2023-01-15'),
('Maria Santos', 6000.00, 'RH', '2022-08-20'),
('Pedro Oliveira', 4500.00, 'Financeiro', '2023-03-10')
-- 1. Primeiro, vamos ver o estado inicial
SELECT 'Estado Inicial dos Funcionários' AS Situacao
SELECT * FROM Funcionarios
SELECT 'Versão atual do Change Tracking: ' + CAST(CHANGE_TRACKING_CURRENT_VERSION() AS VARCHAR(10)) AS Info
-- 2. Simulando última sincronização (salva em tabela de controle)
CREATE TABLE ControleSync (
Sistema VARCHAR(50),
UltimaVersao BIGINT,
DataSync DATETIME2
)
INSERT INTO ControleSync VALUES ('SistemaBI', CHANGE_TRACKING_CURRENT_VERSION(), GETDATE())
Simulando atividades de usuários
-- 3. Agora vamos simular atividade no sistema (várias transações de usuários)
PRINT '--- Simulando atividade de usuários no sistema ---'
-- Usuario 1: Aumento de salário
UPDATE Funcionarios SET Salario = 5800.00 WHERE Nome = 'João Silva'
PRINT 'RH aprovou aumento para João Silva'
-- Usuario 2: Novo funcionário contratado
INSERT INTO Funcionarios (Nome, Salario, Departamento, DataContratacao)
VALUES ('Carlos Mendes', 4800.00, 'TI', '2024-01-15')
PRINT 'Novo funcionário Carlos contratado'
-- Usuario 3: Mudança de departamento
UPDATE Funcionarios SET Departamento = 'Financeiro' WHERE Nome = 'Maria Santos'
PRINT 'Maria transferida para Financeiro'
-- Usuario 4: Funcionário desligado
DELETE FROM Funcionarios WHERE Nome = 'Pedro Oliveira'
PRINT 'Pedro desligado da empresa'
Sincronizando os dados
-- 4. Agora é hora da sincronização! Vamos ver o que mudou
DECLARE @ultima_sync BIGINT = (SELECT UltimaVersao FROM ControleSync WHERE Sistema = 'SistemaBI')
PRINT '--- RESULTADO DA SINCRONIZAÇÃO ---'
PRINT 'Versão da última sync: ' + CAST(@ultima_sync AS VARCHAR(10))
PRINT 'Versão atual: ' + CAST(CHANGE_TRACKING_CURRENT_VERSION() AS VARCHAR(10))
-- 5. Identificando quais registros mudaram
SELECT
'Mudanças detectadas pelo Change Tracking:' AS Titulo
SELECT
CT.ID,
CASE CT.SYS_CHANGE_OPERATION
WHEN 'I' THEN 'INSERIDO'
WHEN'U'THEN'ALTERADO'
WHEN 'D' THEN 'DELETADO'
END AS TipoMudanca,
CT.SYS_CHANGE_VERSION AS VersaoMudanca,
F.Nome,
F.Departamento,
F.Salario
FROM CHANGETABLE(CHANGES Funcionarios, @ultima_sync) AS CT
LEFT JOIN Funcionarios F ON CT.ID = F.ID
ORDER BY CT.SYS_CHANGE_VERSION
-- 6. Para o sistema de BI, pegamos apenas os dados atuais dos registros alterados
SELECT 'Dados para enviar ao BI:' AS FinalSync
SELECT
F.ID,
F.Nome,
F.Salario,
F.Departamento,
F.DataContratacao,
'Dados atualizados para sincronização' AS Status
FROM Funcionarios F
WHERE F.ID IN (
SELECT CT.ID
FROM CHANGETABLE(CHANGES Funcionarios, @ultima_sync) AS CT
WHERE CT.SYS_CHANGE_OPERATION IN ('I', 'U') -- Só inseridos e alterados
)
-- 7. Atualizando controle para próxima sincronização
UPDATE ControleSync
SET UltimaVersao = CHANGE_TRACKING_CURRENT_VERSION(),
DataSync = GETDATE()
WHERE Sistema = 'BaseBI'
PRINT 'Sincronização concluída! Sistema BI atualizado.'
Enfim, existem N maneiras que você pode capturar os dados modificados.
Já o CDC é a escolha certa quando você precisa de auditoria completa, ou seja, quando você precisa saber exatamente o que mudou nos seus dados. É ideal para manter histórico de alterações, especialmente para compliance e regulamentações. Também é a melhor opção para replicação de dados complexa, quando você precisa aplicar as mesmas mudanças em outro sistema mantendo a integridade. E é excelente para análise de comportamento, quando você quer entender como os dados evoluem ao longo do tempo.
Exemplos de uso do CDC
-- Criando banco para CDC
DROP DATABASE IF EXISTS TesteCDC
CREATE DATABASE TesteCDC
USE TesteCDC
GO
-- Habilitando CDC no banco
EXEC sys.sp_cdc_enable_db
-- Criando tabela de produtos
CREATE TABLE Produtos (
ID INT IDENTITY(1,1) PRIMARY KEY,
Nome VARCHAR(100),
Preco DECIMAL(10,2),
Categoria VARCHAR(50),
Estoque INT,
DataUltimaAtualizacao DATETIME2 DEFAULT GETDATE()
)
-- Habilitando CDC na tabela
EXEC sys.sp_cdc_enable_table
@source_schema = 'dbo',
@source_name = 'Produtos',
@role_name = NULL,
@supports_net_changes = 1Inserindo dados iniciais e verificando o estado inicial dos produtos
-- Inserindo dados iniciais
INSERT INTO Produtos (Nome, Preco, Categoria, Estoque)
VALUES
('Notebook Dell Alienware M16', 2500.00, 'Informática', 10),
('Mouse Logitech G903', 50.00, 'Informática', 100),
('Cadeira Gamer DXRacer MX1000', 800.00, 'Móveis', 5)
-- 1. Vamos ver o estado inicial dos produtos
SELECT 'Estado inicial da loja:' AS Situacao
SELECT ID, Nome, Preco, Categoria, Estoque FROM Produtos
Simulando atividades de usuários durante o dia
-- 2. Simulando atividade de vários usuários durante o dia
PRINT '--- SIMULANDO ATIVIDADES DO DIA ---'
-- 08:30 - Gerente ajusta preços para promoção matinal
UPDATE Produtos SET Preco = 2200.00 WHERE Nome = 'Notebook Dell Alienware M16'
PRINT '08:30 - Gerente: Promoção matinal no Notebook (-R$ 300)'
-- 10:15 - Reposição de estoque
UPDATE Produtos SET Estoque = 120 WHERE Nome = 'Mouse Logitech G903'
PRINT '10:15 - Estoque: Reposição de mouses'
-- 14:00 - Promoção especial de tarde
UPDATE Produtos SET Preco = 1950.00 WHERE Nome = 'Notebook Dell Alienware M16'
PRINT '14:00 - Marketing: Super promoção vespertina no Notebook (-R$ 250)'
-- 14:30 - Cliente comprou e diminuiu estoque
UPDATE Produtos SET Estoque = 115 WHERE Nome = 'Mouse Logitech G903'
PRINT '14:30 - Vendas: 5 mouses vendidos'
-- 16:00 - Correção de preço (erro de digitação)
UPDATE Produtos SET Preco = 2100.00 WHERE Nome = 'Notebook Dell Alienware M16'
PRINT '16:00 - Supervisor: Correção de preço do Notebook'
-- 17:00 - Correção de preço (erro de digitação)
UPDATE Produtos SET Preco = 2100.00 WHERE Nome = 'Mouse Logitech G903'
PRINT '17:00 - Supervisor: Correção de preço do Notebook'
-- 18:00 - Produto descontinuado
DELETE FROM Produtos WHERE Nome = 'Cadeira Gamer DXRacer MX1000'
PRINT '18:00 - Gestão: Cadeira Gamer descontinuada'
Auditando as mudanças com o CDC
-- 3. AUDITORIA COMPLETA DO CDC
PRINT ''
PRINT '=== RELATÓRIO DE AUDITORIA COMPLETA ==='
-- QUERY 1: Histórico específico do Notebook (SEM duplicação)
SELECT 'AUDITORIA: Histórico APENAS do Notebook Dell' AS Relatorio
SELECT
c.Nome,
c.Preco AS PrecoRegistrado,
FORMAT(sys.fn_cdc_map_lsn_to_time(c.__$start_lsn), 'dd/MM/yyyy HH:mm:ss') AS MomentoMudanca,
CASE
WHEN c.__$operation = 3 THEN 'Preço ANTES'
WHEN c.__$operation = 4 THEN 'Preço DEPOIS'
END AS TipoPreco
FROM cdc.dbo_Produtos_CT c
WHERE c.__$operation IN (3,4)
AND c.__$update_mask = 0x04 -- Apenas mudanças de preço
AND c.Nome LIKE '%Notebook%' -- APENAS Notebook
ORDER BY c.__$start_lsn
-- QUERY 2: Relatório de TODOS os produtos (diferente da anterior)
SELECT 'RELATÓRIO: Resumo de preços alterados por produto' AS Relatorio
SELECT DISTINCT
c.Nome AS Produto,
COUNT(CASE WHEN c.__$operation = 4 THEN 1 END) AS QtdAlteracoes,
MIN(CASE WHEN c.__$operation = 3 THEN c.Preco END) AS PrecoInicial,
MAX(CASE WHEN c.__$operation = 4 THEN c.Preco END) AS PrecoFinal
FROM cdc.dbo_Produtos_CT c
WHERE c.__$operation IN (3,4)
AND c.__$update_mask = 0x04
GROUP BY c.Nome
-- Auditoria de produtos removidos (para compliance)
SELECT 'AUDITORIA: Produtos removidos do sistema' AS Relatorio
SELECT DISTINCT
c.ID,
c.Nome,
c.Preco AS UltimoPreco,
c.Categoria,
FORMAT(sys.fn_cdc_map_lsn_to_time(c.__$start_lsn), 'dd/MM/yyyy HH:mm:ss') AS DataRemocao
FROM cdc.dbo_Produtos_CT c
WHERE c.__$operation = 1 -- Apenas DELETEs
ORDER BY c.ID
-- Relatório executivo: resumo de atividades
SELECT 'RESUMO : Atividades do dia' AS Relatorio
SELECT
COUNT(CASE WHEN c.__$operation = 2 THEN 1 END) AS ProdutosAdicionados,
COUNT(CASE WHEN c.__$operation = 1 THEN 1 END) AS ProdutosRemovidos,
COUNT(CASE WHEN c.__$operation IN (3,4) THEN 1 END) / 2 AS ProdutosAlterados,
COUNT(DISTINCT c.ID) AS ProdutosAfetados
FROM cdc.dbo_Produtos_CT c
Vamos falar sobre as limitações de cada tecnologia porque isso é importante na hora de escolher. O Change Tracking não armazena valores históricos, os dados são perdidos após o período de retenção, não funciona bem com transações muito grandes e pode ter problemas com operações BULK. Por outro lado, seu overhead é muito baixo, aproximadamente 2-5% de overhead, e não requer espaço adicional significativo.
Já o CDC tem suas próprias limitações. Está disponível apenas nas edições Enterprise, Developer e Express, requer SQL Server Agent rodando, tem maior consumo de espaço em disco e pode impactar performance em ambientes com muitas escritas. Seu overhead é moderado a alto, variando de 10-30% dependendo do volume de mudanças, e requer monitoramento das tabelas de CDC para evitar crescimento excessivo.
Aqui estão alguns scripts que uso no dia a dia para monitorar essas tecnologias.
Para monitorar o Change Tracking :
Validando bases que estão com o Change Tracking habilitado
-- Verificando bancos com Change Tracking habilitado
SELECT
name AS BancoComChangeTracking
FROM sys.databases
WHERE DATABASEPROPERTYEX(name, 'IsChangeTrackingEna
bled') = 1
Validando tabelas com o Change Tracking habilitado
-- Verificando tabelas com Change Tracking habilitado
SELECT
OBJECT_NAME(object_id) AS tabela,
is_track_columns_updated_on,
min_valid_version,
CHANGE_TRACKING_CURRENT_VERSION() AS versao_atual
FROM sys.change_tracking_tables
Para monitorar o CDC:
Validando bases com o CDC habilitado
-- Verificando bancos com CDC habilitado
SELECT name, is_cdc_enabled FROM sys.databases WHERE is_cdc_enabled = 1
Validando tabelas com o CDC habilitado
-- Verificando tabelas com CDC
SELECT
s.name AS schema_name,
t.name AS table_name,
c.capture_instance,
c.object_id,
c.start_lsn
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
JOIN cdc.change_tables c ON t.object_id = c.source_object_id
Monitorando espaço ocupado pelas tabelas do CDC
-- Verificando espaço usado pelas tabelas CDC
SELECT
OBJECT_NAME(object_id) AS tabela_cdc,
SUM(reserved_page_count) * 8.0 / 1024 AS tamanho_mb
FROM sys.dm_db_partition_stats
WHERE object_id IN (SELECT object_id FROM cdc.change_tables)
GROUP BY object_id
No Change Tracking, a limpeza é automática se você configurou AUTO_CLEANUP = ON.
Para o CDC, você precisa ter um pouco mais de cuidado, nos scripts abaixo você verá como consultar o histórico dos Jobs de limpeza do CDC e como forçar um cleanup manual.
-- Verificando jobs de limpeza do CDC
SELECT
j.name,
j.enabled,
ja.run_requested_date,
ja.last_executed_step_date
FROM msdb.dbo.sysjobs j
JOIN msdb.dbo.sysjobactivity ja ON j.job_id = ja.job_id
WHERE j.name LIKE 'cdc.%'
-- Limpeza manual do CDC (se necessário)
DECLARE @cleanup_lsn BINARY(10)
SET @cleanup_lsn = sys.fn_cdc_get_min_lsn('dbo_Produtos')
EXEC sys.sp_cdc_cleanup_change_table
@capture_instance = 'dbo_Produtos',
@low_water_mark = @cleanup_lsn

Algumas dicas que podem te ajudar na decisão sobre qual escolher
- Use Change Tracking quando performance for um fator crítico, e você só precisar de uma sincronização simples, o seu ambiente tiver restrições de espaço em disco ou você estiver trabalhando na versão Standard.
- Use CDC quando precisar de uma auditoria completa da sua tabela com um histórico detalhado da mudança dos dados e para atender questões de compliance, mas levando em conta que pode afetar a performance do seu banco e aumentar consideravelmente o espaço em disco ocupado pelas tabelas.
Conclusão
No final das contas, tanto Change Tracking quanto CDC cumprem o que prometem, só que de formas diferentes. O Change Tracking é mais leve e direto ao ponto. Se você só precisa saber que algo mudou, ele resolve sem complicação. Já o CDC é mais pesado, mas te dá informação completa, quando você precisa de auditoria detalhada, ele entrega tudo que você precisa.
A chave é entender seu cenário específico e escolher a ferramenta certa para o trabalho certo.
Lembre-se de testar sempre em ambiente de homologação antes de implementar em produção.
E vocês? já tiveram experiências com essas tecnologias? Qual escolheram para seus projetos? Compartilhem nos comentários suas experiências e dúvidas!
Espero que esse post tenha esclarecido as diferenças e ajudado vocês a tomarem a decisão certa nos seus projetos.
Qualquer dúvida, deixem nos comentários que quando possível responderei.
Gustavo Larocca
Consultor SQL Server
Referencias :
[Microsoft – Enable and Disable Change Data Capture] – (https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/enable-and-disable-change-data-capture-sql-server?view=sql-server-ver17)
[Microsoft – About Change Tracking] – (https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server?view=sql-server-ver17)
[Microsoft – Work With Change Tracking SQL Server] – (https://learn.microsoft.com/pt-br/sql/relational-databases/track-changes/work-with-change-tracking-sql-server?view=sql-server-ver17)
[Blog – Dirceu Resende] – (https://dirceuresende.com/en/blog/sql-server-como-monitorar-e-auditar-alteracoes-de-dados-em-tabelas-utilizando-change-data-capture-cdc/)
Gostou do conteúdo?
Acompanhe novos artigos sobre SQL Server, performance e administração de banco de dados.
