SQL CLR标量函数缓存结果

Tim*_*all 2 sql-server sqlclr sql-server-2014

一般问题

迁移到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;
Run Code Online (Sandbox Code Playgroud)

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

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

SQL Server 2008 R2中的结果:

20161213502167209995
20161213502168210095
20161213502169210195
20161213502170210295
20161213502171210395
20161213502172210495
20161213502173210595
20161213502174210695
20161213502175210795
20161213502176210895
Run Code Online (Sandbox Code Playgroud)

SQL Server 2014中的结果:

20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
20161213502199924787
Run Code Online (Sandbox Code Playgroud)

我们使用此代码为我们收到的特定类型的每个文件生成特定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());
}
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 6

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

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

IsDeterministic = true
Run Code Online (Sandbox Code Playgroud)

确定性函数为相同的输入值返回相同的值.考虑到你的函数没有任何输入参数,它的所有执行都基本相同.

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

为了解决这个问题,你应该能够设置IsDeterministic = false,或者干脆去掉IsDeterministic = true,,因为默认值IsDeterministicfalse.

PS我知道你说不要争论为什么你有这个特殊的功能,但是如果你(或其他人)不知道它,当前的滴答值应该暴露在DMV中:

SELECT [cpu_ticks] FROM sys.dm_os_sys_info;
Run Code Online (Sandbox Code Playgroud)

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