目的
在尝试创建一个自引用函数的测试示例时,一个版本失败而另一个版本成功。
唯一的区别是在函数体中添加了一个SELECT,导致两者具有不同的执行计划。
工作的函数
CREATE FUNCTION dbo.test5(@i int)
RETURNS INT
AS
BEGIN
RETURN(
SELECT TOP 1
CASE
WHEN @i = 1 THEN 1
WHEN @i = 2 THEN 2
WHEN @i = 3 THEN dbo.test5(1) + dbo.test5(2)
END
)
END;
调用函数
SELECT dbo.test5(3);
返回值
(No column name)
3
无法正常工作的函数
CREATE FUNCTION dbo.test6(@i int)
RETURNS INT
AS
BEGIN
RETURN(
SELECT TOP 1
CASE
WHEN @i = 1 THEN 1
WHEN @i = 2 THEN 2
WHEN @i = 3 THEN (SELECT dbo.test6(1) + dbo.test6(2))
END
)END;
调用函数
SELECT dbo.test6(3);
或者
SELECT dbo.test6(2);
错误结果
超过最大存储过程、函数、触发器或视图的嵌套级别(限制为32)。
猜测原因
在失败的函数的估计计划中存在额外的计算标量调用。
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="CASE WHEN [@i]=(1) THEN (1) ELSE CASE WHEN [@i]=(2) THEN (2) ELSE CASE WHEN [@i]=(3) THEN [Expr1000] ELSE NULL END END END">
And expr1000 being
<ColumnReference Column="Expr1000" />
<ScalarOperator ScalarString="[dbo].[test6]((1))+[dbo].[test6]((2))">
这可能解释了递归引用超过32的原因。
实际问题
添加SELECT会使函数不断地调用自身,导致无限循环,但为什么添加SELECT会产生这样的结果呢?
附加信息
Build version:
14.0.3045.24
在 compatibility_levels 100 和 140 上进行了测试

