问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

什么是变更数据捕获(CDC)?

创作时间:
作者:
@小白创作中心

什么是变更数据捕获(CDC)?

引用
1
来源
1.
https://learn.microsoft.com/zh-tw/sql/relational-databases/track-changes/about-change-data-capture-sql-server?view=sql-server-ver16

什么是变更数据捕获(CDC)?

变更数据捕获(CDC)是一种功能,可以在修改表和行时记录数据库上的活动。本文说明 CDC 如何与 SQL Server 和 Azure SQL 受控实例搭配运作。至于 Azure SQL 数据库,请参阅Azure SQL 数据库的 CDC。

概观

变更数据捕获使用 SQL Server Agent 来记录表中发生的插入、更新和删除操作。因此,它可以让您轻松地使用关系型格式访问这些数据变更。为了将变更数据应用于目标环境,系统会捕获修改后行所需的列数据和基本元数据,然后将这些变更数据存储在变更表中。这些表会根据被跟踪的源表的列结构进行镜像。此外,用户可以通过表值函数系统地访问这些变更数据。

这种技术的理想目标数据使用者是提取、转换和加载(ETL)应用程序。ETL 应用程序以累积方式,将变更数据从 SQL Server 源表加载到数据仓库或数据集市。虽然在数据仓库内的源表表示形式必须反映源表中的变更,但是端到端的重新整理源副本的技术并不适用。相反,您需要一个可靠且有结构的变更数据流,以便消费者能够将其应用于不同的数据目标形式。SQL Server 变更数据捕获提供了这项技术。

数据流程

下图显示变更数据捕获的主要数据流程。

变更数据捕获的变更数据源是 SQL Server 事务日志。当插入、更新和删除操作应用于跟踪源表时,描述这些变更的项就会添加到日志中。此日志作为捕获过程的输入。然后,它会读取日志并将变更的相关信息添加到关联的变更表。系统提供了一些函数,以便枚举出现在变更表中的指定范围内的变更,并以筛选结果集的形式返回此信息。应用程序处理程序通常会使用筛选结果集,在某些外部环境中更新源的表现形式。

捕获实例

您必须先针对数据库明确启用变更数据捕获,然后才能跟踪该数据库内部任何个别表的变更。此操作是使用 sys.sp_cdc_enable_db 存储过程完成的。启用数据库之后,您可以使用 sys.sp_cdc_enable_table 存储过程,将源表标识为跟踪表。当某个表启用变更数据捕获时,系统就会创建关联的捕获实例,以便支持源表中变更数据的传播。此捕获实例包含一个变更表以及最多两个查询函数。描述捕获实例的配置详细信息的元数据会包含在变更数据捕获元数据表 cdc.change_tablescdc.index_columnscdc.captured_columns 中。您可以使用 sys.sp_cdc_help_change_data_capture 存储过程来获取此信息。

与捕获实例相关的所有对象都会在已启用数据库的变更数据捕获结构中创建。捕获实例名称的要求包括其必须是有效的对象名称,而且其在数据库捕获实例中必须是唯一的。默认名称为源表的 <schema_name>_<table_name>。其关联变更表的命名方式是将 _CT 附加到捕获实例名称。用于查询所有变更的函数的命名方式是在捕获实例名称前面加上 fn_cdc_get_all_changes_。如果捕获实例设置为支持网络变更,系统也会创建 net_changes 查询函数,而且其命名方式是在捕获实例名称前面加上 fn_cdc_get_net_changes_

重要
可同时与单个源表关联的捕获实例数量上限是二。

变更表

变更数据捕获变更表的前五个列是元数据列。这些数据会提供与已记录之变更相关的额外信息。其余列则会镜像源表中识别之捕获列的名称,通常也会镜像其类型。这些列保存的是从源表中收集并捕获的数据。

应用于源表的每个插入或删除操作会在变更表中显示为单个行。插入操作所产生的行的列包含了插入后的列值。删除操作所产生的行的列包含删除之前的列值。更新操作需要一个行项目来识别更新之前的列值,和第二个行项目来识别更新之后的列值。

变更表中的每个行也会包含其他元数据,以便允许解释变更活动。列 __$start_lsn 识别被分配给该变更的提交日志序列号(LSN)。提交 LSN 用于标识相同事务中提交的变更,并为这些事务排序。列 __$seqval 可用于排序在同一事务中发生的其他变更。列 __$operation 会记录与变更相关的操作:1 = 删除、2 = 插入、3 = 更新(建立数据影像前),以及 4 = 更新(建立数据影像后)。列 __$update_mask 是变量位掩码,其中每个捕获列都有一个定义的位。如果是插入和删除项目,更新掩码会设置所有位。但是,更新行将仅会设置对应于已更改之列的位。

有效间隔

数据库的变更数据捕获有效性间隔就是捕获实例可以使用变更数据的时间范围。有效性间隔始于您为数据库表创建第一个捕获实例时,并持续至今。

数据库

如果您没有定期且有系统地清除存储在变更表中的数据,这些数据将难以管理地增长。变更数据捕获清除处理程序负责强制执行保留性清除原则。首先,它会移动有效性间隔的低端点,以满足时间限制。然后,它会移除过期的变更表项目。默认情况下,系统会保留三天内的数据。

对于高层次而言,当捕获程序认可每批新的变更数据时,新记录会添加到具有变更表记录的每个事务的 cdc.lsn_time_mapping 中。在对应表中,会保留提交记录序列号(LSN)和事务提交时间(分别为主键列 start_lsntran_end_time)。在 cdc.lsn_time_mapping 中找到的最大 LSN 值代表数据库有效性期间的上限标准。其对应的提交时间用作基于保留的清理计算新下限标记的基础。

由于捕获程序会从事务日志中捕获变更数据,因此源表认可变更的时间与变更显示在其关联变更表中的时间之间具有内置的延迟。虽然这个延迟通常很小,但仍然要记住,在捕获过程处理相关日志条目之前,变更数据是无法获取的。

捕获实例

虽然数据库有效性间隔与个别捕获实例的有效性间隔通常会一致,但并非永远如此。当捕获程序识别捕获实例并开始将相关联的变更记录到其变更表时,捕获实例的有效性间隔就开始了。因此,如果您在不同的时间创建捕获实例,每个捕获实例都会有不同的低端点。sys.sp_cdc_help_change_data_capture 返回的结果集的 start_lsn 列会显示每个已定义捕获实例的当前低端点。当清理程序清除变更表项目时,它会调整所有捕获实例的 start_lsn 值,以反映新的可用变更数据的低水位标记。只有 start_lsn 值目前小于新下限标准的这些捕获实例才会进行调整。经过一段时间后,如果没有创建任何新的捕获实例,所有个别实例的有效性间隔通常会与数据库有效性间隔一致。

变更数据的有效性区间对于使用者来说非常重要,因为对于捕获请求,其捕获区间必须完全被捕获实例的当前变更数据捕获有效性区间所涵盖。如果捕获区间的低端点位于有效性区间的低端点的左边,可能会由于积极的清除而丢失变更数据。如果捕获区间的高端点位于有效性区间的高端点的右边,表示捕获程序尚未完全处理捕获区间所代表的时间,而且也可能会丢失变更数据。

sys.fn_cdc_get_min_lsn 函数用于捕获捕获实例的当前最小 LSN,而 sys.fn_cdc_get_max_lsn 则用于捕获当前最大 LSN 值。查询变更数据时,如果指定的 LSN 范围并未落在这两个 LSN 值之内,变更数据捕获查询函数将会失败。

处理源表的变更

对下游使用者来说,应对正在被跟踪的源表的列变更是一个棘手的问题。虽然针对源表启用变更数据捕获无法避免这类 DDL 变更发生,但是变更数据捕获可通过保留通过 API 返回的已传递结果集来减轻对使用者的影响,即使基础源表的列结构变更也一样。这个固定的列结构也会反映在已定义之查询函数所访问的基础变更表中。

负责填充变更表的捕获程序会忽略源表启用变更数据捕获时未识别为捕获的任何新列,以容纳固定列结构的变更表。如果删除某个跟踪列,在后续的变更项目中将为该列提供空值。但是,如果现有列进行数据类型的变更,此变更会被传播到变更表,以确保捕获机制不会导致跟踪列的数据丢失。此外,捕获程序还会将检测到的所有变更记录到跟踪表的列结构中,并写入到 cdc.ddl_history 表。想要收到可能必须在下游应用程序中完成之调整警示的使用者,会使用 sys.sp_cdc_get_ddl_history 存储过程。

一般而言,当 DDL 变更应用于关联的源表时,当前捕获实例将继续保留其外观。然而,可以为表创建一个反映新列结构的第二个捕获实例。此选项允许捕获程序对相同的源表进行变更,并将其转录到具有两种不同列结构的两个不同变更表中。因此,当某个变更表可以继续满足目前运行中的程序时,第二个变更表可以驱动尝试纳入新列数据的开发环境。允许捕获机制一前一后扩展这两个变更表表示,系统可以完成这两个表之间的转换,而不会丢失变更数据。当两个变更数据捕获表重叠时,就可能会发生这种情况。当过渡受到影响时,可以移除已废弃的捕获实例。

重要
可同时与单个源表关联的捕获实例数量上限是二。

与日志读取器代理程序的关系

变更数据捕获处理程序的逻辑嵌入在存储过程 sp_replcmds 中,此存储过程是构建为 sqlservr.exe 一部分的内部服务器函数,也会由变更复制用来从事务日志中收集变更。在 SQL Server 和 Azure SQL 受控实例中,当您针对某个数据库单独启用变更数据捕获时,就会将变更数据捕获 SQL Server Agent 捕获作业创建为调用 sp_replcmds 的工具。当复制也存在时,仅使用事务日志读取器来满足这两个使用者的变更数据需求。当您针对相同的数据库同时启用复制和变更数据捕获时,此策略可大幅减少日志竞争的情况。

每当启用变更数据捕获之数据库的复制状态变更时,就会自动在这两种捕获变更数据的作业模式之间切换。

注意
在 SQL Server 和 Azure SQL 受控实例中,捕获逻辑的两个执行实例都需要 SQL Server Agent 处于运行状态,才能执行程序。

捕获程序的主要任务是扫描日志,并将列数据和事务相关信息写入变更数据捕获的变更表。为了确保其填充的所有变更数据捕获变更表保持事务一致性边界,捕获程序会在每个扫描循环中开启并提交自己的事务。它会检测出表最近启用变更数据捕获的时间,并自动将它们加入目前正在记录中监视变更项目的表集合。同样地,关闭变更数据捕获也会被检测到,导致源数据表从正在监控变化数据的表集合中移除。当某个日志区段的处理完成时,捕获程序就会发出服务器日志截断逻辑的信号,而此逻辑会使用这信息来识别适合用于截断的日志项。

重要
启用变更数据捕获的数据库时,即使恢复模式设置为简单恢复,在捕获程序收集到所有标记为待捕获的变更之前,日志截断点将不会前进。如果捕获程序并未执行,而且存在要收集的变更,执行 CHECKPOINT 将不会截断日志。

捕获流程也用于维护跟踪表的 DDL 变更的历史记录。每当卸除启用变更数据捕获的数据库或表,或是加入、修改或卸除启用变更数据捕获之表的列时,与变更数据捕获相关联的 DDL 语句就会在数据库事务日志中建立项目。捕获程序会先处理这些日志项目,然后将相关联的 DDL 事件发布到 cdc.ddl_history 表。您可以使用 sys.sp_cdc_get_ddl_history 存储过程来获取有关影响跟踪表之 DDL 事件的相关信息。

警告

  • MaxCmdsInTran 的设计不是为了要永远开启。其存在的目的是为了解决有人不小心在单一事务中执行大量 DML 操作的情况,这会导致在整个事务进入分发数据库之前,命令的分发延迟、锁持续存在等问题。如果您经常遇到这种情况,请检查您的应用程序逻辑,并找出减少事务大小的方法。
  • 如果指定的发布数据库同时启用 CDC 和复制,则不支持 MaxCmdsInTran。在此设置中使用 MaxCmdsInTran 可能会导致 CDC 变更表中的数据丢失。如果在复制大型事务时新增和移除 MaxCmdsInTran 参数,也可能造成 PK 错误。

代理作业

通常有两个 SQL Server Agent 作业与启用变更数据捕获的数据库相关联:一个用于填充数据库变更表的作业,以及一个负责变更表清理的作业。这两个作业都包含执行 Transact-SQL 命令的单一步骤。所调用的 Transact-SQL 命令是定义为变更数据捕获的存储过程,它实现了作业的逻辑。当数据库的第一个表启用变更数据捕获时,系统就会创建这些作业。系统一定会创建清理作业。只有在数据库没有任何已定义的事务性发布集的情况下,才会创建捕获作业。当您针对数据库同时启用变更数据捕获和事务性复制时,系统也会创建捕获作业,并移除事务日志读取器作业,因为数据库不再有任何已定义的发布项目。

捕获和清理作业都是使用默认参数创建的。捕获作业会立即启动。它会连续执行,并在每个扫描循环中最多处理 1000 个事务(循环之间等待 5 秒)。清理作业会在每天上午 2 点执行,它会保留变更表项目长达 4320 分钟或 3 天,而且单个删除语句最多可以移除 5000 个项目。

当您针对数据库停用变更数据捕获时,系统就会移除变更数据捕获代理程序作业。在启用变更数据捕获和变更复制的条件下,当第一个发布集加入到数据库时,也可以选择移除捕获作业。

就内部而言,变更数据捕获代理程序作业是分别使用 sys.sp_cdc_add_jobsys.sp_cdc_drop_job 存储过程创建和卸除的。系统也公开了这些存储过程,让管理员能够控制这些作业的创建和移除。

管理员对于变更数据捕获代理程序作业的默认配置没有明确的控制权。sys.sp_cdc_change_job 存储过程的提供目的是允许修改默认配置参数。此外,sys.sp_cdc_help_jobs 存储过程则允许查看当前的配置参数。捕获作业和清理作业都会在启动时从 msdb.dbo.cdc_jobs 表中获取配置参数。使用 sys.sp_cdc_change_job 对这些值所做的任何更改,要等到此作业停止并重新启动时才会生效。

系统提供了另外两个存储过程,让您可以启动和停止变更数据捕获代理程序作业:sys.sp_cdc_start_jobsys.sp_cdc_stop_job

注意
启动和停止捕获作业不会导致变更数据丢失。它只会影响捕获程序主动扫描日志,以搜索并存储在变更表中的变更项目。避免日志扫描在高峰需求期间增加负载的合理策略是停止捕获作业,然后在需求降低时重新启动它。

这两个 SQL Server Agent 作业都设计成具备足够的弹性并且可以充分地进行配置,以符合变更数据捕获环境的基本需求。但是,在这两种情况下,系统都已经公开提供了核心功能的基础存储过程,方便您进一步自定义。

以 NETWORK SERVICE 帐户身份执行 Database Engine 服务或 SQL Server Agent 服务时,变更数据捕获无法正确运行。这可能会导致错误 22832。

与其他功能的互操作性

使用其他 SQL Server 功能时,变更数据捕获有一些限制。参阅互操作性以深入了解。

已知问题

如需与变更数据捕获相关的已知问题和错误,请参阅 CDC 的已知问题。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号