CDC fn_cdc_get_all_changes_dbo_ error 313“参数数量不足......”

时间:2014-07-16 10:59:39

标签: sql-server sql-server-2012 cdc

不缺少涵盖此功能和错误的主题"为过程或函数cdc.fn_cdc_get_all_changes"提供的参数数量不足。我已经检查了大部分内容,但无法弄清楚是什么错误。

这里的问题特别是我无法重现这一点。它只是每天或两次随机出现几次,并且在几秒钟内消失,所以通常我只能在作业历史中看到它作为失败的运行。

我浏览过的所有资源都表示,它通常来自于使用该功能从捕获实例没有数据的时间范围内获取数据。但是,正如下面的代码将向您展示的那样,在运行函数之前,仅检查这些类型的异常值。

DECLARE @END_LSN BINARY(10), @MIN_TABLE_LSN BINARY(10);
SELECT @END_LSN = sys.fn_cdc_get_max_lsn();

SELECT @MIN_TABLE_LSN = MAX(__$start_lsn) FROM MY_AUDIT_TABLE

IF @MIN_TABLE_LSN IS NOT NULL
    SELECT @MIN_TABLE_LSN = sys.fn_cdc_increment_lsn(@MIN_TABLE_LSN)
ELSE
    SELECT @MIN_TABLE_LSN = sys.fn_cdc_get_min_lsn('dbo_MY_AUDIT_TABLE')

IF @MIN_TABLE_LSN IS NOT NULL
BEGIN
    INSERT INTO MY_AUDIT_TABLE (...columns...)
    SELECT  ... columns...
    FROM cdc.fn_cdc_get_all_changes_dbo_MY_SOURCE_TABLE(@MIN_TABLE_LSN, @END_LSN, 'all update old') C
    JOIN cdc.lsn_time_mapping T WITH (NOLOCK) ON T.start_lsn = C.__$start_lsn
    ORDER BY __$start_lsn ASC, __$seqval ASC
END

现在,有些人甚至建议的唯一剩余的替代方案是,此代码有时可能会从AUDIT表中选择最新的更改,然后将其增加到尚未存在的LSN。但是我已经手动测试了很多次,而且没有错误。此外,使用从另一个CDC表派生的@END_LSN值,此特定的MY_AUDIT_TABLE目前还没有记录,也可以完美地运行。

我手动产生此错误的唯一方法是为函数提供比lsn_time_mapping表中存在的更新的@END_LSN值。但是这样的场景只有在SQL Server能够用lsn_time_mapping中尚未存在的start_lsn实际创建CDC表记录的情况下才有可能,我几乎认为不可能。或者是吗?这意味着您无法在行刚刚可用时将lsn可靠地映射到日期时间。

像往常一样,再次感谢您的帮助和解释。 :)

3 个答案:

答案 0 :(得分:2)

这个

SELECT @MIN_TABLE_LSN = sys.fn_cdc_increment_lsn(@MIN_TABLE_LSN)

只需在@MIN_TABLE_LSN中添加1即可。新的@Min_Table_Lsn不一定存在。因此,如果您没有任何更改,@ END_LSN可能低于@Min_Table_Lsn并且cdc.fn_cdc_get_all_changes_dbo_MY_SOURCE_TABLE()函数可能会失败。

请注意,“CDC扫描程序作业”每隔5分钟向cdc.lsn_time_mapping表添加一个虚拟LSN(事务ID为0x0),这就是为什么在没有更改且脚本可能成功或不成功的情况下可能出现的情况,具体取决于当你运行它时。

如上所述,您应该更改Min LSN低于或等于End LSN

的条件

答案 1 :(得分:1)

我能够通过使用“全名”来解决此问题

例如。表是 dbo.lookup_test ,您需要在 sys.fn_cdc_get_min_lsn 中通过 dbo_lookup_test

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

显然,上面的代码已经考虑了我的答案,但是表命名要求“ {schema} _ {tablename}”并不明显,并且SQL Server无法通过提供误导性的错误消息来提供帮助。

请注意,lsn应该声明为 binary(10)。它不能简单地声明为二进制。它将引发相同的错误。

答案 2 :(得分:0)

简单 - 如果您尝试提供给get_all_changes函数的BeginLsn / FromLsn在更改表中不可用,则抛出此错误。默认情况下,将其设置为minLsn(get_min_lsn)并将其传递给function。保留期有效,每隔x天后,更改表数据将被清除,因此您应确保将FromLsn设置为CT表中的可用值。