当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

时间:2022-05-10 23:56:24

In the following t-sql statement, how many times will the dbo.FUNC function get called?

在下面的t-sql语句中,dbo.FUNC函数被调用多少次?

SELECT
    column1,
    column2,
    dbo.FUNC(column3) AS column3
FROM table1
WHERE dbo.FUNC(column3) >= 5
ORDER BY dbo.FUNC(column3) DESC

Will it called multiple separate times per row, or does the optimizer recognize that it is being used multiple times in a single statement, and only call it once?

它会在每行调用多个单独的时间,还是优化器会识别出它在单个语句中被多次使用,并且只调用一次?

How can I test this? I can't insert into a table inside of a function, so incrementing a counter wont work...

我该怎么测试呢?我无法插入函数内的表中,因此递增计数器不会工作...

3 个解决方案

#1


11  

This isn't guaranteed.

这不保证。

You would need to check the execution plan to find out. Some examples.

您需要检查执行计划以找出答案。一些例子。

CREATE FUNCTION dbo.FUNC1(@p1 int)
RETURNS int
AS
BEGIN
    RETURN @p1 + 1
END

GO

CREATE FUNCTION dbo.FUNC2(@p1 int)
RETURNS int
WITH SCHEMABINDING
AS
BEGIN
    RETURN @p1 + 1
END

GO
SELECT 
       OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC1'), 'IsDeterministic'),
       OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC2'), 'IsDeterministic') 
GO

FUNC2 is created WITH SCHEMABINDING and is treated as deterministic. FUNC1 isn't.

FUNC2是使用SCHEMABINDING创建的,并被视为确定性的。 FUNC1不是。

SELECT
    dbo.FUNC1(number) AS FUNC1,
    dbo.FUNC2(number) AS FUNC2
FROM master..spt_values
WHERE dbo.FUNC1(number) >= 5 AND dbo.FUNC2(number) >= 5
ORDER BY dbo.FUNC1(number), dbo.FUNC2(number)

Gives Plan

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
       |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
            |--Filter(WHERE:([test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])>=(5) AND [Expr1004]>=(5)))
                 |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])))
                      |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

FUNC1 is evaluated twice (once in the filter and once in a compute scalar outputting a calculated column used for both the projection and the ordering), FUNC2 is only evaluated once.

FUNC1被评估两次(一次在滤波器中,一次在计算标量输出用于投影和排序的计算列),FUNC2仅被评估一次。

Rewriting as

SELECT
    FUNC1,
    FUNC2
FROM master..spt_values
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2)
WHERE FUNC1 >= 5 AND FUNC2 >= 5
ORDER BY FUNC1, FUNC2

Changes the plan slightly and both are only evaluated once

略微更改计划,两者仅评估一次

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
       |--Filter(WHERE:([Expr1003]>=(5)))
            |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
                 |--Filter(WHERE:([Expr1004]>=(5)))
                      |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])))
                           |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

Now making a slight alteration to the query

现在对查询稍作修改

SELECT
    FUNC1 + 10,
    FUNC2 + 10
FROM master..spt_values
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2)
WHERE FUNC1 >= 5 AND FUNC2 >= 5
ORDER BY FUNC1, FUNC2

Gives the opposite of the original result in that FUNC2 is evaluated twice but FUNC1 only once.

与原始结果相反,FUNC2被评估两次但FUNC1仅被评估一次。

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Compute Scalar(DEFINE:([Expr1005]=[Expr1003]+(10)))
       |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
            |--Filter(WHERE:([Expr1003]>=(5)))
                 |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
                      |--Filter(WHERE:([Expr1004]>=(5)))
                           |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number]), [Expr1006]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])+(10)))
                                |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

#2


1  

Firstly, it depends on if the function is deterministic.

首先,它取决于函数是否是确定性的。

Even then, that will only be used for multiple calls on a single row.

即便如此,这只会用于单行上的多个调用。

I believe your case would be optimized if the function is deterministic.

如果函数是确定性的,我相信你的情况会被优化。

#3


-2  

yes.

the optimizer has the sufficient knowledge to optimize this into a same calc while running.

优化器具有足够的知识,可以在运行时将其优化为相同的calc。

you can look at the execution plan to see it.

您可以查看执行计划以查看它。

#1


11  

This isn't guaranteed.

这不保证。

You would need to check the execution plan to find out. Some examples.

您需要检查执行计划以找出答案。一些例子。

CREATE FUNCTION dbo.FUNC1(@p1 int)
RETURNS int
AS
BEGIN
    RETURN @p1 + 1
END

GO

CREATE FUNCTION dbo.FUNC2(@p1 int)
RETURNS int
WITH SCHEMABINDING
AS
BEGIN
    RETURN @p1 + 1
END

GO
SELECT 
       OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC1'), 'IsDeterministic'),
       OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC2'), 'IsDeterministic') 
GO

FUNC2 is created WITH SCHEMABINDING and is treated as deterministic. FUNC1 isn't.

FUNC2是使用SCHEMABINDING创建的,并被视为确定性的。 FUNC1不是。

SELECT
    dbo.FUNC1(number) AS FUNC1,
    dbo.FUNC2(number) AS FUNC2
FROM master..spt_values
WHERE dbo.FUNC1(number) >= 5 AND dbo.FUNC2(number) >= 5
ORDER BY dbo.FUNC1(number), dbo.FUNC2(number)

Gives Plan

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
       |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
            |--Filter(WHERE:([test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])>=(5) AND [Expr1004]>=(5)))
                 |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])))
                      |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

FUNC1 is evaluated twice (once in the filter and once in a compute scalar outputting a calculated column used for both the projection and the ordering), FUNC2 is only evaluated once.

FUNC1被评估两次(一次在滤波器中,一次在计算标量输出用于投影和排序的计算列),FUNC2仅被评估一次。

Rewriting as

SELECT
    FUNC1,
    FUNC2
FROM master..spt_values
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2)
WHERE FUNC1 >= 5 AND FUNC2 >= 5
ORDER BY FUNC1, FUNC2

Changes the plan slightly and both are only evaluated once

略微更改计划,两者仅评估一次

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
       |--Filter(WHERE:([Expr1003]>=(5)))
            |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
                 |--Filter(WHERE:([Expr1004]>=(5)))
                      |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])))
                           |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

Now making a slight alteration to the query

现在对查询稍作修改

SELECT
    FUNC1 + 10,
    FUNC2 + 10
FROM master..spt_values
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2)
WHERE FUNC1 >= 5 AND FUNC2 >= 5
ORDER BY FUNC1, FUNC2

Gives the opposite of the original result in that FUNC2 is evaluated twice but FUNC1 only once.

与原始结果相反,FUNC2被评估两次但FUNC1仅被评估一次。

当对同一个UDF的多次调用都在一个语句中时,它会被调用多少次?

  |--Compute Scalar(DEFINE:([Expr1005]=[Expr1003]+(10)))
       |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC))
            |--Filter(WHERE:([Expr1003]>=(5)))
                 |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])))
                      |--Filter(WHERE:([Expr1004]>=(5)))
                           |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number]), [Expr1006]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])+(10)))
                                |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))

#2


1  

Firstly, it depends on if the function is deterministic.

首先,它取决于函数是否是确定性的。

Even then, that will only be used for multiple calls on a single row.

即便如此,这只会用于单行上的多个调用。

I believe your case would be optimized if the function is deterministic.

如果函数是确定性的,我相信你的情况会被优化。

#3


-2  

yes.

the optimizer has the sufficient knowledge to optimize this into a same calc while running.

优化器具有足够的知识,可以在运行时将其优化为相同的calc。

you can look at the execution plan to see it.

您可以查看执行计划以查看它。