Captura de data e hora da alteração no CDC do SQL Server

8

Então, começamos a explorar o uso da captura de dados alterados em um de nossos bancos de dados de produção. Gostaríamos de saber a data e hora de cada alteração. Lendo orientações e tutoriais, etc., parece que a abordagem padrão é usar o LSN para se relacionar com a cdc.lsn_time_mappingtabela do sistema. Essa abordagem funciona, mas não é muito direta nem eficaz quando se fala de centenas de milhares de alterações por dia.

Em um ambiente de teste, fiz o seguinte ajuste nas tabelas de alterações. Emiti uma ALTER TABLEdeclaração para adicionar uma coluna ao final chamada [__ChangeDateTime]e fiz seu valor padrão GetDate(). A abordagem parece funcionar, o controle de alterações ainda funciona normalmente, os datetime estão sendo capturados. Mas mexer nas mesas do sistema me deixa um pouco nervoso.

Se esse não é um campo do sistema que a Microsoft adicionou desde o início, eles devem ter seus motivos. Como eles optaram pelo LSN para a abordagem cdc.lsn_time_mapping, eu estou me preparando para problemas criando meu próprio hack dessa maneira?

ATUALIZAR:

Descoberto durante o teste que GetDate () às vezes não é preciso o suficiente para nossas necessidades - várias alterações compartilhando ao mesmo tempo. Recomenda o uso de sysdatetime () e datetime2 para mover o valor para o nanossegundo. Opção para 2008+ apenas obviamente.

RThomas
fonte

Respostas:

8

Lembre-se de que o CDC usa um agente de leitor de log para preencher a tabela de alterações. Por que isso é importante? Por esse mecanismo, as linhas são exibidas nas tabelas de alterações de forma assíncrona com as alterações feitas nas tabelas base.

Na verdade, existem três pontos de tempo diferentes que podem ser registrados, em ordem cronológica reversa:

  1. O horário em que a alteração foi entregue na tabela de alterações (que é o que você está gravando).
  2. O horário em que a transação que continha a alteração foi confirmada (usando cdc.lsn_time_mapping).
  3. O horário com o qual você preenche manualmente uma coluna na tabela base (usando uma restrição padrão, um gatilho etc.).

Portanto, a primeira coisa é deixar claro o que você deseja gravar. Normalmente, nos importamos com o nº 2 ou o nº 3.

Se o mecanismo de mapeamento LSN (# 2) não estiver funcionando bem o suficiente para você, a única alternativa suportada é adicionar uma coluna à tabela base e preenchê-la você mesmo (# 3).

No que diz respeito à alteração das tabelas internas, por uma questão de política, acho melhor evitar hackear os internos quando houver alternativas suportadas. A última coisa que você deseja é que um importante sistema de produção seja desativado, precise ligar para o Suporte ao produto e ter o serviço negado por causa de algo assim. Não se preocupe com os problemas de quebrar coisas potencialmente (atualizações) ou ser quebrado porque foi inesperado (desligue o CDC e ligue-o novamente, conforme mencionado na outra resposta).

Jon Seigel
fonte
3

Um exemplo prático:

USE Database;
GO

DECLARE @from_lsn binary(10), @to_lsn binary(10)
SET @from_lsn = sys.fn_cdc_get_min_lsn('schema_tablename')
SET @to_lsn = sys.fn_cdc_get_max_lsn()

SELECT
    sys.fn_cdc_map_lsn_to_time(__$start_lsn) AS 'Time'
    ,[Field1]
    ,[Field2]
    ,[Field3]
FROM [cdc].[fn_cdc_get_all_changes_schema_tablename]
  (@from_lsn, @to_lsn, N'all');
Gareth Orrill
fonte
Esta resposta se beneficiaria de alguns comentários explicando o que você está fazendo e por que é relevante.
Erik
2

A única ressalva que eu daria é que essas tabelas são descartadas automaticamente quando o CDC está desativado. A coluna não pode ser recriada automaticamente quando você a renova

Liam Confrey
fonte