【问题标题】: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 在这里应该是确定性的,因为我将它用于字符串->整数。

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

【问题讨论】:

    标签: sql user-defined-functions deterministic non-deterministic


    【解决方案1】:

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

    【讨论】:

    【解决方案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 模式?这表明不确定性,但我只是推测。

      【讨论】:

        猜你喜欢
        • 2018-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-08
        • 2016-07-01
        • 1970-01-01
        • 2020-11-04
        相关资源
        最近更新 更多