捕获SQL Server CDC中更改的日期时间


8

因此,我们已经开始探索在我们的一个生产数据库中使用变更数据捕获。我们想知道每次更改的日期时间。通读演练和教程等内容,似乎标准方法是使用LSN与cdc.lsn_time_mapping系统表相关。当谈论一天中成千上万的变化时,这种方法行得通,但不是很简单,也不是很有效。

在测试环境中,我对变更跟踪表进行了以下调整。我发表了一条ALTER TABLE声明,在末尾添加一列,[__ChangeDateTime]并将其设置为默认值GetDate()。该方法似乎有效,更改跟踪仍然正常运行,捕获了日期时间。 但是混用系统表会让我有些紧张。

如果这不是Microsoft从一开始添加系统字段,则必须说明其原因。由于他们改而选择了LSN来cdc.lsn_time_mapping方法,我是否通过以这种方式创建自己的hack来解决问题?

更新:

在测试过程中发现,有时GetDate()不够精确,无法满足我们的需求-多个更改同时共享。建议使用sysdatetime()和datetime2将值移至纳秒级。显然只有2008年以上的选项。

Answers:


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');

此答案将受益于一些注释,这些注释解释了您在做什么以及为何相关。
Erik

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.