函数被调用多少次

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

以上是关于函数被调用多少次的主要内容,如果未能解决你的问题,请参考以下文章

Golang之不可重入函数实现

Keras 中的 .fit() 方法触发损失函数多少次

C++ 函数中静态变量的生命周期是多少?

C++ 函数中静态变量的生命周期是多少?

计算函数被调用的次数

在matlab里调用一个函数,怎么知道它计算过程中迭代了多少次呢