Why does SQL Server say this function is nondeterministic?

孤人 提交于 2019-12-13 02:53:38

问题


Execute this function in T-SQL:

CREATE FUNCTION [dbo].[Parse_URI_For_Scheme](
         @URI nvarchar(4000))
RETURNS nvarchar(250)
WITH SCHEMABINDING
AS
BEGIN

   DECLARE @temp_string varchar(4000)
   DECLARE @return_string nvarchar(250)
   DECLARE @pos int

   SET @pos = CHARINDEX('://', @URI);
   --select @pos
   IF @pos > 0
      BEGIN
         SET @temp_string = SUBSTRING(@URI, 0, @pos);

         -- SET @pos = CHARINDEX('/', @temp_string)

         IF @pos > 0
            BEGIN
               SET @temp_string = LEFT(@temp_string, @pos - 1);

               SET @pos = CHARINDEX('@', @temp_string);

               IF @pos > 0
                  SET @return_string = SUBSTRING(@temp_string, @pos + 1, 250);
               ELSE
                  SET @return_string = @temp_string;
            END
         ELSE
            SET @return_string = '';
      END
   ELSE
      SET @return_string = '';

   RETURN @return_string;

END;

Then execute this command which returns 0:

SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].Parse_URI_For_Scheme'), 'IsDeterministic')

Can someone please tell me why this is not a deterministic function?


回答1:


One of the key points for SQL Server to mark a function as Deterministic is the SchemaBinding feature. For your function to be deterministic you need to define the function using With SchemaBinding.

In Your example if you remove the With SchemaBinding, the ObjectProperty function will return 0 for the IsDeterministic attribute, so by adding the With SchemaBinding the problem will be resolved for you

@Paul has detailed explanation around this issue, here




回答2:


Vahid's gave a great reply. I agree with everything he said and love the link to the Paul White comment which is excellent.

A couple things to note:

1. The logic you're using is overly complex for what you are trying to do.

I think you could get away with:

SUBSTRING(@URI, 1, ISNULL(NULLIF(CHARINDEX('://', @URI)-1,0),''))

2. If you must have a function for this task use an inline Table Valued Function (iTVF).

This advice changed my career and what I've learned over the years is that there are two kinds of T-SQL functions: iTVFs and very slow functions (e.g. Scalar and multi-statement table valued functions). Here's more great reading from Paul White on this topic: Understanding and Using APPLY (Part 1).

Let's turn your function into a high-performing, parallelism-enabled DETERMINISITC function.

CREATE FUNCTION dbo.parse_uri_for_scheme_itvf(@URI nvarchar(4000))
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT newURI = SUBSTRING(@URI, 1, ISNULL(NULLIF(CHARINDEX('://', @URI)-1,0),''));

and a performance test to demonstrate why scalar functions are not for people in a hurry.

Sample Data

SELECT string = cast(pr+'://'+samples.txt as nvarchar(4000))
INTO #strings
FROM (VALUES ('http'),('https'),('ftp')) pr(pr)
CROSS JOIN 
(
  SELECT replicate(newid(), abs(checksum(newid())%2)+1)
  FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) a(x),
       (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) b(x),
       (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) c(x),
       (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) d(x),
       (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) e(x)
) samples(txt);

Perf Test

SET NOCOUNT ON;
PRINT 'Scalar'+char(10)+replicate('-',60);
GO
DECLARE @st datetime = getdate(), @txt nvarchar(4000);
SELECT @txt = dbo.Parse_URI_For_Scheme(t.string)
FROM #strings t;
PRINT datediff(ms,@st,getdate())
GO 3

PRINT 'iTVF'+char(10)+replicate('-',60);
GO
DECLARE @st datetime = getdate(), @txt nvarchar(4000);
SELECT @txt = itvf.newURI
FROM #strings t
CROSS APPLY dbo.parse_uri_for_scheme_itvf(t.string) itvf;
PRINT datediff(ms,@st,getdate())
GO 3

Results

Scalar
------------------------------------------------------------
Beginning execution loop
1423
1380
1360
Batch execution completed 3 times.

iTVF
------------------------------------------------------------
Beginning execution loop
423
427
437
Batch execution completed 3 times.

I knew the iTVF would be 3-4 times faster before I prepared the test.



来源:https://stackoverflow.com/questions/48468523/why-does-sql-server-say-this-function-is-nondeterministic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!