为啥 SQL 2005 说这个 UDF 是不确定的?

Posted

技术标签:

【中文标题】为啥 SQL 2005 说这个 UDF 是不确定的?【英文标题】:Why does SQL 2005 say this UDF is non-deterministic?为什么 SQL 2005 说这个 UDF 是不确定的? 【发布时间】:2009-02-20 20:14:25 【问题描述】:

我有以下功能:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO    
ALTER FUNCTION [dbo].[IP4toBIGINT](
    @ip4 varchar(15)
) 
RETURNS bigint
WITH SCHEMABINDING
AS
BEGIN
    -- oc3 oc2 oc1 oc0
    -- 255.255.255.255
    -- Declared as BIGINTs to avoid overflows when multiplying later on     DECLARE @oct0 bigint, @oct1 bigint, @oct2 bigint, @oct3 bigint;
    DECLARE @Result bigint;

    SET @oct3 = CAST(PARSENAME(@ip4, 4) as tinyint);
    SET @oct2 = CAST(PARSENAME(@ip4, 3) as tinyint);
    SET @oct1 = CAST(PARSENAME(@ip4, 2) as tinyint);
    SET @oct0 = CAST(PARSENAME(@ip4, 1) as tinyint);

    -- Combine all values, multiply by 2^8, 2^16, 2^24 to bitshift.
    SET @Result = @oct3 * 16777216 + @oct2 * 65536 + @oct1 * 256 + @oct0;
    RETURN @Result;

END

但是……

SELECT 
     OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsDeterministic') as IsDeterministic 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsPrecise') as IsPrecise 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsSystemVerified') as IsSystemVerified 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'SystemDataAccess') as SystemDataAccess 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'UserDataAccess') as UserDataAccess 

返回(结果转置):

确定性 0

精确 1

IsSystemVerified 1

系统数据访问 0

用户数据访问 0

我尝试多次删除并重新创建该函数,以确保它不是缓存问题。 CAST 在这里应该是确定性的,因为我将它用于字符串->整数。

我完全被难住了,有什么想法吗?

【问题讨论】:

【参考方案1】:

PARSENAME 总体上是不确定的。是的,您在确定性的上下文中使用它,但我猜服务器不知道这一点。尝试替换 PARSENAME,看看它是否改变。

【讨论】:

MSDN 声明 PARSENAME 始终是确定性的 没试过,但相信MSDN。 Downvote 消失和 +1。 :-) 你说得对,它是 PARSENAME,我被 MSDN 甩了,它明确表示它是:msdn.microsoft.com/en-us/library/ms178091(SQL.90).aspx【参考方案2】:

这是导致问题的 PARSENAME。用硬编码字符串替换它会导致确定性。不知道为什么... parse name 应该只是一个花哨的拆分函数。

看看这个:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO    
ALTER FUNCTION [dbo].[IP4toBIGINT](
    @ip4 varchar(15)
) 
RETURNS bigint
WITH SCHEMABINDING
AS
BEGIN
    -- oc3 oc2 oc1 oc0
    -- 255.255.255.255
    -- Declared as BIGINTs to avoid overflows when multiplying later on         
    DECLARE @oct0 bigint, @oct1 bigint, @oct2 bigint, @oct3 bigint;
    DECLARE @Result bigint;

    SET @oct3 = CAST('1' as tinyint);
    SET @oct2 = CAST('2' as tinyint);
    SET @oct1 = CAST('3' as tinyint);
    SET @oct0 = CAST('4' as tinyint);

    -- Combine all values, multiply by 2^8, 2^16, 2^24 to bitshift.
    SET @Result = @oct3 * 16777216 + @oct2 * 65536 + @oct1 * 256 + @oct0

    RETURN @Result
END
GO

SELECT 
     OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsDeterministic') as IsDeterministic 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsPrecise') as IsPrecise 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'IsSystemVerified') as IsSystemVerified 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'SystemDataAccess') as SystemDataAccess 
    ,OBJECTPROPERTYEX(OBJECT_ID('dbo.IP4toBIGINT'), 'UserDataAccess') as UserDataAccess

结果:

IsDeterministic IsPrecise IsSystemVerified  SystemDataAccess UserDataAccess
1               1         1                 0                0

【讨论】:

【参考方案3】:

嗯,是的,所以问题确实是使用 PARSENAME。 MSDN explicitly says 它是确定性的。也许这是因为 SQL 假设您将读取 DB 模式?这表明不确定性,但我只是推测。

【讨论】:

以上是关于为啥 SQL 2005 说这个 UDF 是不确定的?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 T-SQL 中的 LAG 函数是不确定的?

用户定义的函数 SQL Server 2005 被错误地标记为非确定性?

SQL Server 2005 标量 UDF 性能

在 SQL Server 2005 中创建 UDF 时出错

SQL server 2005 为何插入汉字显示问号,修改也修改不了,为啥啊?求解

当我使用UDF操作列时,它有问题