必须先启用数据库级CDC,再为表启用捕获;启用需db_owner权限,执行sys.sp_cdc_enable_db后须查sys.databases.is_cdc_enabled=1确认生效,cdc架构延迟至首张表启用时创建。

必须先启用数据库级 CDC,再为具体表开启捕获,否则 sys.sp_cdc_enable_table 会静默失败或报权限错误。
启用数据库 CDC 的前提和验证方式
只有 db_owner 角色成员才能执行 sys.sp_cdc_enable_db。运行后不会立即创建 cdc schema —— 它只在首次为某张表启用 CDC 后才出现。常见误判是执行完 EXEC sys.sp_cdc_enable_db 就以为成功,结果后续调用 sys.sp_cdc_enable_table 报错 “The database is not enabled for Change Data Capture”。
- 验证是否真正启用:查询
SELECT is_cdc_enabled FROM sys.databases WHERE name = DB_NAME(),返回1才算生效 - 如果返回
0,检查是否在正确数据库上下文中执行(USE your_db; GO) - Azure SQL 数据库不支持
SQL Server Agent,但内置调度器会自动接管捕获作业,无需手动启停
为单张表启用 CDC 时的三个关键参数
sys.sp_cdc_enable_table 的 @capture_instance、@role_name 和 @supports_net_changes 直接影响后续查询能力和权限控制:
-
@capture_instance建议显式指定(如N'HumanResources_Employee'),避免系统自动生成带下划线的长名(如HumanResources_Employee_123456789),否则函数名cdc.fn_cdc_get_all_changes_<capture_instance></capture_instance>难以记忆和维护 -
@role_name若设为NULL,则所有用户只要对源表有SELECT权限就能查变更数据;若指定角色(如'cdc_reader'),必须让使用者成为该角色成员,否则查cdc.fn_cdc_get_all_changes_*会报Msg 229, Level 14, State 5 -
@supports_net_changes = 1才能使用cdc.fn_cdc_get_net_changes_*函数,否则只能查所有变更(含中间更新态),无法直接拿到“最终净变化”
查询变更数据时 LSN 边界必须严格校验
所有 CDC 表值函数(如 cdc.fn_cdc_get_all_changes_*)都依赖两个 LSN 参数:from_lsn 和 to_lsn。传入非法值不会返回空集,而是直接报错 Msg 313 —— 这个错误信息完全不提示真实原因,极易误导。
- 务必用
sys.fn_cdc_get_min_lsn('capture_instance')获取当前有效下界,不能硬编码0x00000000000000000000 -
to_lsn必须 ≤sys.fn_cdc_get_max_lsn()返回值,且不能等于sys.fn_cdc_get_min_lsn()(否则范围为空) - 连续拉取时,下次的
from_lsn应为本次查询中最大__$start_lsn+ 1,用sys.fn_cdc_increment_lsn(@last_lsn)计算,不能简单加 1(LSN 是 binary(10),非数值) - 若用时间映射 LSN(
sys.fn_cdc_map_time_to_lsn),注意该函数返回的是“≤ 指定时间”的最大 LSN,可能漏掉同一毫秒内多个事务
DDL 变更(如加列)后必须重新同步捕获实例
对已启用 CDC 的表执行 ALTER TABLE ... ADD COLUMN 后,新列默认不会出现在变更表中,也不会被 cdc.fn_cdc_get_all_changes_* 返回 —— 即使你重跑 sys.sp_cdc_enable_table 也不起作用。
- 必须调用
sys.sp_cdc_get_ddl_history确认 DDL 已记录,并观察required_column_update = 1 - 此时需手动执行
sys.sp_cdc_refresh_table_change_data(SQL Server 2022+)或重建捕获实例(禁用再启用) - Azure SQL 数据库暂不支持
sp_cdc_refresh_table_change_data,只能删掉原捕获实例后重新sp_cdc_enable_table,期间会有短暂断点 - 排序规则不一致(如
VARCHAR列用Chinese_PRC_CI_AI而库用SQL_Latin1_General_CP1_CI_AS)会导致中文等非 ASCII 字符捕获乱码,改用NVARCHAR是最稳妥解法
LSN 不是时间戳,它不可预测、不可跨库比较,且每次查询后必须推进;DDL 变更不是“热更新”,它需要显式刷新或重建,这两点最容易被当成透明能力而踩坑。

















