如何清除 MS SQL 中 cdc table 中的所有条目?

How to clean up all entries in a cdc table in MS SQL?

阅读微软文档这是相关的系统过程: sys.sp_cdc_cleanup_change_table

我试过这样使用它:

DECLARE @max_lsn binary(10);
SET @max_lsn = sys.fn_cdc_get_max_lsn();
Exec sys.sp_cdc_cleanup_change_table
@capture_instance = N'dbo_mytable',
@low_water_mark = @max_lsn;

查询已成功执行,但再次检查 table 查询:

DECLARE @from_lsn binary(10), @to_lsn binary(10);
SET @from_lsn = sys.fn_cdc_get_min_lsn('dbo_mytable');
SET @to_lsn   = sys.fn_cdc_get_max_lsn();
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_mytable
  (@from_lsn, @to_lsn, N'all');

仍然 returns 一个非空 table。我对 SQL 不太熟悉。我错过了什么?

我为此构建了一个小测试,是的,我看到了同样的事情。我花了几分钟才弄清楚发生了什么事。

“陷阱”是文档中的这个小条目:

If other entries in cdc.lsn_time_mapping share the same commit time as the entry identified by the new low watermark, the smallest LSN associated with that group of entries is chosen as the low watermark.

换句话说,如果 sys.fn_cdc_get_max_lsn() 的结果映射到 cdc.lsn_time_mapping.tran_begin_time 并且还具有其他关联的 start_lsn 值,那么清理过程实际上不会使用sys.fn_cdc_get_max_lsn() 的值作为新的低水位线。

换句话说,如果您要清理的当前更改 table 中的最大 lsn 与其他 LSN 具有相同的 tran_begin_time,并且它不是那些 LSN 中最低的,您无法“完全”清除更改 table。

在这些情况下进行彻底清理的最简单方法可能是对目标进行微小更改 table 以提高最大 lsn 并强制执行新条目,并“希望”新条目也不与具有相同传输开始时间的任何其他 LSN 相关联。

为了更明确,这是我的小测试。 运行 一遍又一遍的结果是,在某些情况下预计清理会失败(并失败),而在其他情况下预计会成功(并成功)。

/*
one time setup:

create table t(i int primary key, c char);
create table u(i int primary key, d char);
go

exec sp_cdc_enable_db;
go

exec sys.sp_cdc_enable_table @source_schema = 'dbo', 
                             @source_name = 't',     
                             @supports_net_changes = 1,
                             @role_name = null;

exec sys.sp_cdc_enable_table @source_schema = 'dbo',   
                             @source_name = 'u',       
                             @supports_net_changes = 1,
                             @role_name = null;
*/
set nocount on;

delete from t;
delete from u;
go

insert t select 1, 'a';
insert u select 1, 'b';
waitfor delay '00:00:01';
go

declare @fail int;

select   @fail = count(*)
from     cdc.lsn_time_mapping 
where    tran_begin_time = (
   select   tran_begin_time 
   from     cdc.lsn_time_mapping 
   where    start_lsn = sys.fn_cdc_get_max_lsn()
);

print iif(@fail > 1, 'this wont do the cleanup you expect', 'this will do the cleanup');

DECLARE @max_lsn binary(10) = sys.fn_cdc_get_max_lsn();
Exec sys.sp_cdc_cleanup_change_table
   @capture_instance = N'dbo_t',
   @low_water_mark = @max_lsn;
go

if exists (select * from cdc.dbo_t_ct) print 'did not cleanup';
else print 'did the cleanup';