目的
尝试创建自引用功能的测试示例时,一个版本失败,而另一个版本成功。
唯一的区别是添加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">
而expr1000被
<ColumnReference Column="Expr1000" />
<ScalarOperator ScalarString="[dbo].[test6]((1))+[dbo].[test6]((2))">
这可以解释递归引用超过32。
实际问题
增加的内容SELECT
使函数反复调用自身,从而导致无限循环,但是为什么要增加SELECT
结果呢?
附加信息
Build version:
14.0.3045.24
经过兼容性级别100和140的测试