函数被调用多少次
Posted
技术标签:
【中文标题】函数被调用多少次【英文标题】:How many times is function called 【发布时间】:2016-05-03 10:19:03 【问题描述】:让我们有以下查询:
SELECT * FROM tablename WHERE ColumnId = dbo.GetId()
其中 dbo.GetId() 是非确定性的用户定义函数。问题是 dbo.GetId() 是否只为整个查询调用一次,然后应用其结果,还是为每一行调用它?我认为每一行都会调用它,但我不知道如何证明它。
跟踪查询也会更有效吗?
DECLARE @Id int
SET @Id = dbo.GetId()
SELECT * FROM tablename WHERE ColumnId = @Id
【问题讨论】:
在函数内部增加一个特定值(表格行中的一个int值),你就会知道。 答案是肯定的。 因为无法知道dbo.GetId()
函数的预期输出,所以它每行执行函数。
@dotNET - 这将是一个令人印象深刻的成就,因为 DML 在函数内部被禁止。
您在这里有什么具体要求?您是否正在寻找某种类型的保证,如果是,是什么形式?它被称为至少一次,最多一次,恰好一次,每行?
【参考方案1】:
我怀疑这在任何地方都能得到保证。如果要确保它,请使用变量。
我修改了@Prdp 的例子
CREATE VIEW vw_rand
AS
SELECT Rand() ran
GO
/*Return 0 or 1 with 50% probability*/
CREATE FUNCTION dbo.Udf_non_deterministic ()
RETURNS INT
AS
BEGIN
RETURN
(SELECT CAST(10000 * ran AS INT) % 2
FROM vw_rand)
END
go
SELECT *
FROM master..spt_values
WHERE dbo.Udf_non_deterministic() = 1
在这种情况下,它只被评估一次。要么返回所有行,要么返回零。
原因是该计划有一个带有启动谓词的过滤器。
启动表达式谓词是[tempdb].[dbo].[Udf_non_deterministic]()=(1)
。
这仅在打开过滤器时评估一次,以查看是否从子树中获取行 - 而不是针对通过它的每一行。
但相反,以下每次返回不同数量的行,表明它是按行计算的。与列的比较可以防止它在过滤器中被预先评估,就像前面的示例一样。
SELECT *
FROM master..spt_values
WHERE dbo.Udf_non_deterministic() = (number - number)
而且这种重写可以追溯到评估一次(对我而言),但CROSS APPLY
仍然给出了多次评估。
SELECT *
FROM master..spt_values
OUTER APPLY(SELECT dbo.Udf_non_deterministic() ) AS C(X)
WHERE X = (number - number)
【讨论】:
感谢您的信息。 :) 我会保留我的答案,仅供您的答案参考【参考方案2】:这是一种证明方法
查看
创建视图是为了在user defined function
中添加一个Nondeterministic
内置函数
CREATE VIEW vw_rand
AS
SELECT Rand() ran
非确定性函数
现在使用上面的视图创建一个Nondeterministic user defined Functions
CREATE FUNCTION Udf_non_deterministic ()
RETURNS FLOAT
AS
BEGIN
RETURN
(SELECT ran
FROM vw_rand)
END
示例表
CREATE TABLE #test
(
id INT,
name VARCHAR(50)
)
INSERT #test
VALUES (1,'a'),
(2,'b'),
(3,'c'),
(4,'d')
SELECT dbo.Udf_non_deterministic (), *
FROM #test
结果:
id name non_deterministic_val
1 a 0.203123494465542
2 b 0.888439497446073
3 c 0.633749721616085
4 d 0.104620204364744
正如您所看到的,所有行都调用了该函数
【讨论】:
【参考方案3】:是的,它确实每行调用一次。 有关调试功能,请参见以下线程 SQL Functions - Logging
是的,下面的查询很有效,因为该函数只被调用一次。
DECLARE @Id int
SET @Id = dbo.GetId()
SELECT * FROM tablename WHERE ColumnId = @Id
【讨论】:
PRINT
在函数中是一个副作用运算符,因此它不允许您在 FUNCTION
中使用 PRINT
。以上是关于函数被调用多少次的主要内容,如果未能解决你的问题,请参考以下文章