1. 新增字段
SQL Server 数据源作为管道任务来源端时,目前 DDL 同步功能 不支持自动同步源端新增字段,若需要使用 DDL 进行新增字段的处理,请参见本文提供的方案。
1.1 方案一:在线方案
注:此方案如果源表在不停写入数据,源表新增字段之后,没有立刻创建新的 CDC 实例,那么在源表新增字段之后到新的 CDC 实例创建前的这段时间中,源表发生的数据修改是不会写入到新的 CDC 实例中的。这可能会导致部分数据丢失新增字段的数据,如果要完全避免这种情况,请采用离线处理方案。
1)源表执行 DDL,新增一个字段。

2)给源表新建一个 Capture Instance
使用命令:
EXEC sys.sp_cdc_enable_table
@source_schema = N'Schema',
@source_name = N'Table',
@role_name = NULL, -- 如果要限制读取角色,可能需要设置
@capture_instance = N'Schema_Table_newname'; -- 给一个新的名字
注:Table 是数据表的名称(没有 schema)。
3)等待 FineDataLink 检测到新的 Capture Instance 创建后,自动切换到新的 Capture Instance
即可看到目标表中已经同步新增的字段,如下图所示:

4)可以手动把旧的 Capture Instance 删除。
检查 change_tables 中旧的 Capture Instance 名称:
USE database;
GO
EXECUTE sys.sp_cdc_help_change_data_capture;
GO
然后禁用该 Capture Instance ,示例命令:
-- Disable a Capture Instance for a table
EXEC sys.sp_cdc_disable_table
@source_schema = N'Schema',
@source_name = N'Table',
@capture_instance = N'Schema_Table'
注:Table 是数据表的名称(没有 schema );Schema_Table 为需要删除的旧 Capture Instance 。
然后使用如下命令检查 change_tables 里是否有这条记录,若没有则表示已经被删除,若有的话需要手动使用 SQL 命令删除。
USE database;
GO
EXECUTE sys.sp_cdc_help_change_data_capture;
GO
1.2 方案二:离线处理方案
1)源表停止写入,等待 FineDataLink 同步完源表所有的数据。
2)停止管道任务。
3)源表执行 DDL,新增一个字段:

4)给源表新建一个 Capture Instance
使用命令:
EXEC sys.sp_cdc_enable_table
@source_schema = N'Schema',
@source_name = N'Table',
@role_name = NULL, -- 如果要限制读取角色,可能需要设置
@capture_instance = N'Schema_Table_newname'; -- 给一个新的名字
5)恢复源表写入。
6)启动管道任务。
7)等待 FineDataLink 检测到新的 Capture Instance 创建后,自动切换到新的 Capture Instance
即可看到目标表中已经同步新增的字段,如下图所示:

8)可以手动删除旧的 Capture Instance。
注:如果没有按照正确顺序操作,可能造成部分有新字段的数据流入了旧的 CDC 实例,那么这部分新字段的数据就丢失了。
2. 修改字段类型
2.1 最佳实践建议
SQL Server CDC 表在源表进行 DDL 变更时可能会因数据类型转换失败而停止工作。由于一个数据库只有一个 capture 作业,一个表的问题会影响所有表的 CDC 功能,会导致实时管道任务因 CDC 表数据停止更新而无法正常同步数据。
针对上述问题,有以下建议:
| 建议类型 | 说明 |
|---|---|
| 预防措施 |
|
| 监控措施 |
|
2.2 CDC无效后的解决方案
2.2.1 问题描述
SQL Server 的 CDC capture 任务突然停止运行。
日志中显示错误:"数据类型值的转换失败"。
管道任务因 CDC 表数据停止更新而无法正常同步数据。
2.2.2 CDC工作原理简介
SQL Server CDC(变更数据捕获)的工作原理如下:
当对库和表开启 CDC 后,SQL Server 会创建一张与原表结构几乎相同的CDC表(以_CT结尾)。
SQL Server 会启动一个 capture 作业,定期解析数据库事务日志。
Capture 作业将事务日志中的变动数据(插入、更新、删除)记录到对应的 CDC 表中。
CDC 表默认保留 3 天的变动记录,超过时限的数据会被自动清理。
FDL 管道任务定时读取 CDC 表中的变动记录,将其同步到目标端。
重要:一个数据库只有一个 capture 作业,如果一个表出现问题,所有表的 CDC 都会停止工作。
2.2.3 直观模拟问题场景
源表中有 varchar 类型字段 col1。
对该表启用 CDC 后,在源表中插入一条带有"aa"字符串的数据,然后又删除了这条数据。
此时源表中已经没有这条数据,但 CDC 表中会有两条记录(一条插入记录,一条删除记录)。
源表字段改为 date 类型,操作成功(因为源表中没有不兼容的数据)。
SQL Server 自动尝试在 CDC 表应用此变更,但因"aa"无法转为日期,变更失败。
Capture 任务终止,所有表的 CDC 都停止工作。
棘手的是:SQL Server 的错误信息不会明确指出是哪个表哪个字段导致了问题。
2.2.5 解决方案
提供两种解决方案,方案对比参考下表:
| 方案一「推荐该方案」 | 方案二 |
|---|---|
优点:
| 优点:
缺点:
|
方案一:Truncate CDC表+重启capture「推荐」
1)以下是一个用于清空(Truncate)所有CDC表的存储过程,可以用来快速解决CDC因数据类型不匹配而停止的问题:
CREATE PROCEDURE dbo.TruncateAllCDCTables
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX) = N'';
DECLARE @crlf NCHAR(2) = NCHAR(13) + NCHAR(10);
-- 生成truncate所有CDC表的SQL语句
SELECT @sql = @sql + 'TRUNCATE TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id))
+ '.' + QUOTENAME(name) + ';' + @crlf
FROM sys.tables
WHERE OBJECT_SCHEMA_NAME(object_id) = 'cdc'
AND name LIKE '%_CT';
-- 打印生成的SQL(可选,用于调试)
-- PRINT @sql;
-- 停止CDC capture进程
EXEC sys.sp_cdc_stop_job;
-- 执行truncate操作
EXEC sp_executesql @sql;
-- 启动CDC capture进程
EXEC sys.sp_cdc_start_job;
PRINT '所有CDC表已清空,CDC capture进程已重启。';
END
2)执行存储过程
-- 执行存储过程,清空所有CDC表并重启capture进程
EXEC dbo.TruncateAllCDCTables;
方案二:重建CDC
关闭所有表的 CDC。
重新开启所有表的 CDC。
重新配置所有 FDL 管道任务
