Захват даты и времени изменений в SQL Server CDC

8

Итак, мы начали исследовать использование сбора данных об изменениях в одной из наших производственных баз данных. Мы хотели бы знать дату и время каждого изменения. Читая пошаговые руководства, учебные пособия и т. Д., Кажется, что стандартный подход заключается в использовании LSN для связи с cdc.lsn_time_mappingсистемной таблицей. Этот подход работает, но он не очень прост и не эффективен, когда речь идет о сотнях тысяч изменений в день.

В тестовой среде я внес следующие изменения в таблицы отслеживания изменений. Я выпустил ALTER TABLEоператор для добавления столбца в конец [__ChangeDateTime]и сделал его значением по умолчанию GetDate(). Подход, кажется, работает, отслеживание изменений все еще работает нормально, дата и время фиксируются. Но возиться с системными таблицами заставляет меня немного нервничать.

Если это не системное поле, которое Microsoft добавила с самого начала, у них должны были быть свои причины. Так как они вместо этого выбрали LSN для подхода cdc.lsn_time_mapping, я настраиваю себя на проблемы, создавая свой собственный взлом таким образом?

ОБНОВИТЬ:

Во время тестирования было обнаружено, что GetDate () порой не является достаточно точным для наших нужд - несколько изменений делятся одновременно. Рекомендуется использовать sysdatetime () и datetime2 для перемещения значения в наносекунду. Вариант на 2008+ только очевидно.

RThomas
источник

Ответы:

8

Помните, что CDC использует агент чтения журнала для заполнения таблицы изменений. Почему это важно? Благодаря этому механизму строки отображаются в таблицах изменений асинхронно с изменениями, внесенными в базовые таблицы.

Фактически можно записать 3 разных момента времени в обратном хронологическом порядке:

  1. Время, когда изменение было доставлено в таблицу изменений (это то, что вы записываете).
  2. Время транзакции, в которой зафиксировано изменение (использование cdc.lsn_time_mapping).
  3. Время, когда вы вручную заполняете столбец в базовой таблице (с использованием ограничения по умолчанию, триггера и т. Д.).

Итак, первое, что нужно понять, что вы хотите записать. Обычно мы заботимся о # 2 или # 3.

Если механизм сопоставления LSN (# 2) работает недостаточно хорошо, единственная поддерживаемая альтернатива - добавить столбец в базовую таблицу и заполнить его самостоятельно (# 3).

Что касается изменения внутренних таблиц, в соответствии с политикой, я думаю, что лучше избегать взлома внутренних компонентов, когда есть поддерживаемые альтернативы. Последнее, что вам нужно, - это отключение важной производственной системы, необходимость вызвать службу поддержки и отказ в обслуживании из-за чего-то подобного. Не берите в голову проблемы его потенциальной поломки (обновления) или поломки, потому что это было неожиданно (выключите CDC, затем включите снова, как упомянуто в другом ответе).

Джон Сайгель
источник
3

Практический пример:

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');
Гарет Оррил
источник
Этот ответ будет полезен некоторыми комментариями, объясняющими, что вы делаете, и почему это важно.
Эрик
2

Единственное предостережение, которое я хотел бы дать, это то, что эти таблицы удаляются автоматически, когда CDC отключен. Столбец не будет воссоздан автоматически при повторном включении

Лиам Конфрей
источник