【问题标题】:SQL CLR Scalar Function cached resultsSQL CLR 标量函数缓存结果
【发布时间】:2017-04-29 03:29:22
【问题描述】:

一般问题

迁移到 SQL Server 2014 后,以前在 SQL Server 2008 R2 中每次执行都会产生不同结果的 CLR 标量函数的执行,现在每次后续调用都会产生相同的结果。

测试/插图

DECLARE @i int = 0;
WHILE @i < 10
 BEGIN
    print dbo.getEligLoadTXID();
    --> Simulate delay as this code never gets called more than once every few seconds in our environment
    WAITFOR DELAY '00:00:00.1';
    SET @i += 1;
 END;

我们目前正在将我们的环境从 SQL Server 2008 R2 升级到 SQL Server 2014。我们遇到的问题之一是特定于 CLR 标量函数的执行。功能比较简单;它正在根据滴答数生成一个内部 ID(我们不要争论这个函数的需求/目的)。

在 SQL Server 2008 R2 环境中,在循环中执行函数会返回预期结果(每次执行都会产生一个新值)。但是,在我们的新 SQL Server 2014 环境中进行测试时,相同的代码会为循环中的每次执行返回相同的值。

SQL Server 2008 R2 中的结果:

20161213502167209995
20161213502168210095
20161213502169210195
20161213502170210295
20161213502171210395
20161213502172210495
20161213502173210595
20161213502174210695
20161213502175210795
20161213502176210895

SQL Server 2014 中的结果:

20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787

我们使用此代码为我们收到的每个特定类型的文件生成一个特定 ID。为每个文件生成一个新值,但处理此问题的 SSIS 进程通常需要 4-5 秒来处理每个文件。所以,这个函数每隔几秒就会被调用一次,来自完全不同的连接,但我们仍然得到重复的结果。

返回值确实是周期性变化的,所以并不是整天只取回一个值,而是在一段时间内,无论是 3 秒还是 30 秒,函数都会返回相同的结果。

我们缺少什么?

CLR 函数定义

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static String getTransactionID()
{
    DateTime NOW = DateTime.Now;

    long ticks = NOW.Ticks - new DateTime(NOW.Year, NOW.Month, NOW.Day, 0, 0, 0, 0).Ticks;

    return String.Format("{0:0000}{1:00}{2:00}{3}", NOW.Year, NOW.Month, NOW.Day, ticks.ToString());
}

【问题讨论】:

    标签: sql-server sql-server-2014 sqlclr


    【解决方案1】:

    这是预期的行为,从 SQL Server 2012 开始。

    问题是您已通过SqlFunction 属性指定该函数应被视为“确定性”:

    IsDeterministic = true
    

    确定性函数对相同的输入值返回相同的值。并且考虑到您的函数没有任何输入参数,它的所有执行基本上是相同的。

    这种行为对于真正确定性的函数来说是一个巨大的性能提升。但是,由于您的函数应该在每次执行时返回不同的值,因此它实际上不是确定性的。

    要解决此问题,您应该能够设置IsDeterministic = false,或者直接删除IsDeterministic = true,,因为IsDeterministic 的默认值为false

    附:我知道你说过不要争论为什么你有这个特定的功能,但只是提一下,以防你(或其他人)不知道,当前的刻度值应该暴露在 DMV 中:

    SELECT [cpu_ticks] FROM sys.dm_os_sys_info;
    

    P.P.S.输入参数和返回值最好使用Sql* 类型。意思是,使用SqlString 而不是String 作为返回类型。这可能需要添加using System.Data.SqlTypes;

    【讨论】:

    • 感谢您的回复!您不仅回答了我的问题,还提供了大量后续细节。
    猜你喜欢
    • 2011-10-17
    • 1970-01-01
    • 2010-11-13
    • 2010-10-12
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    相关资源
    最近更新 更多