sql-server - 当在同一条语句中多次调用同一UDF时,它将被调用多少次?

标签 sql-server tsql

在下面的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

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

我该如何测试?我无法插入函数内部的表中,因此增加计数器将无法工作...

最佳答案

这不能保证。

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

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被创建为WITH 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)

制定计划
  |--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评估两次(在过滤器中一次,在计算标量中一次,输出用于投影和排序的计算列),FUNC2仅评估一次。

改写为
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

略微更改计划,并且都只评估一次
  |--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]))

现在对查询稍作改动
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

与原始结果相反,对FUNC2进行两次评估,但对FUNC1进行一次评估。
  |--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]))

关于sql-server - 当在同一条语句中多次调用同一UDF时,它将被调用多少次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8964834/

相关文章:

sql - MS SQL Server - 游标什么时候好?

sql - 如何跨行组合 SQL 中的二进制 block ?

sql-server - 在列中显示 n 个电话号码

mysql - 是否有用于远程数据应用程序的 MS SQL Compact Edition 的开源替代品?

php - 如何在选择查询中获取行号

sql - 获取月份的最后一天 (SQL Server 2008R2)

sql-server - SQL 服务器 : using MERGE statement to update two tables

sql - SQL Server 中临时表的使用

Java 1.8.0 在 JDBC 连接中启用 TLS1.2

sql-server - 从 openxml 中选择,将多个节点值连接到一个字符串