【问题标题】:CDC fn_cdc_get_all_changes_dbo_ error 313 "An insufficient number of arguments..."CDC fn_cdc_get_all_changes_dbo_ 错误 313“参数数量不足...”
【发布时间】:2019-01-18 06:21:11
【问题描述】:

不乏涵盖此函数的主题和错误“为过程或函数 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 可以实际创建带有 start_lsn 且在 lsn_time_mapping 中尚不存在的 CDC 表记录时才有可能,而且我认为这几乎是不可能的。或者是吗?这意味着您无法在该行刚刚可用时可靠地将 lsn 映射到日期时间。

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

【问题讨论】:

  • 正如您所说,我只在 LSN 参数表示无意义区间(即 min >= max)时看到此错误。我的建议是用if @min_table_lsn < @end_lsn 替换您的支票,因为这需要正确才能使获取更改功能正常工作。
  • 是的,但我不明白为什么我无法重现该问题。我怀疑该函数使用一些 math.Random() 函数在我测试它时使用更大的 min > max 值可以很好地工作,但是当作业和过程执行相同的操作时有时会返回错误?但是,是的,我想我会尝试一下,看看接下来几天我是否会遇到这些错误。谢谢! :)
  • 发生了奇怪的事情。我唯一的建议是记录过程中的值。我不能告诉你你会发现什么,但它几乎可以保证很有趣。

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


【解决方案1】:

这个

SELECT @MIN_TABLE_LSN = sys.fn_cdc_increment_lsn(@MIN_TABLE_LSN)

只需将 1 加到 @MIN_TABLE_LSN。没有必要存在新的@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 的条件

【讨论】:

    【解决方案2】:

    我可以通过使用“全名”来解决这个问题

    例如。表是 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)。它不能简单地声明为二进制。它会抛出同样的错误。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-17
        • 1970-01-01
        • 2016-05-22
        • 2018-09-21
        • 1970-01-01
        相关资源
        最近更新 更多