让我们有以下查询:
SELECT * FROM {tablename} WHERE ColumnId = dbo.GetId()
其中dbo.GetId()是非确定性用户定义函数。问题是dbo.GetId()是否只对整个查询调用一次,然后应用其结果还是为每一行调用?我认为每一行都需要它,但我不知道如何证明它。
此外,查询会更有效吗?
DECLARE @Id int
SET @Id = dbo.GetId()
SELECT * FROM {tablename} WHERE ColumnId = @Id
答案 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
在这种情况下,它只被评估一次。要么返回所有行,要么返回零。
原因是该计划有一个带有启动谓词的过滤器。
启动表达式谓词是[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)
答案 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