函数调用了多少次

时间:2016-05-03 10:19:04

标签: sql-server

让我们有以下查询:

SELECT * FROM {tablename} WHERE ColumnId = dbo.GetId()

其中dbo.GetId()是非确定性用户定义函数。问题是dbo.GetId()是否只对整个查询调用一次,然后应用其结果还是为每一行调用?我认为每一行都需要它,但我不知道如何证明它。

此外,查询会更有效吗?

DECLARE @Id int
SET @Id = dbo.GetId()
SELECT * FROM {tablename} WHERE ColumnId = @Id

3 个答案:

答案 0 :(得分:3)

我怀疑这在任何地方都有保障。如果要确保它,请使用变量。

我修改了@ 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

在这种情况下,它只被评估一次。要么返回所有行,要么返回零。

原因是该计划有一个带有启动谓词的过滤器。

enter image description here

启动表达式谓词是[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)

enter image description here

答案 1 :(得分:1)

这是证明它的一种方法

视图

创建视图是为了在Nondeterministic

中添加user defined function内置函数
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

正如您所看到的那样,函数被称为

答案 2 :(得分:0)

是的,每行调用一次。 有关调试功能,请参见以下线程 SQL Functions - Logging

是的,以下查询是有效的,因为该函数只被调用一次。

DECLARE @Id int
SET @Id = dbo.GetId()
SELECT * FROM {tablename} WHERE ColumnId = @Id