TSQL:避免内联函数中的 MAXRECURSION 限制

Posted

技术标签:

【中文标题】TSQL:避免内联函数中的 MAXRECURSION 限制【英文标题】:TSQL: avoid MAXRECURSION limit in a inline function 【发布时间】:2016-06-15 09:14:50 【问题描述】:

我有这个函数,给定一个初始日期和最后一个日期,给出该范围内的相应年/月:

CREATE FUNCTION [dbo].[fnYearMonth]
(
    @Initial Date,
    @Final Date 
)
RETURNS TABLE 
AS
RETURN
With dateRange(StatDate) as 
(
    select @Initial
    union all
    select dateadd(month, 1, StatDate)
    from dateRange 
    where dateadd(month, 1, StatDate) <= CAST(DATEADD(month,DATEDIFF(month,0,@Final)+1,0)-1 as Date)
)
select DATEPART(year, StatDate) AS MyYear, DATEPART(month, StatDate) AS MyMonth From dateRange where StatDate <= @Final

问题在于 MAXRECURSION 的默认限制为 100 只提供最多 8 年零 4 个月的可用日期范围。这还不够。

我尝试使用“OPTION (MAXRECURSION 2000);”在使用此函数但不起作用的函数中,因为我在 WITH 语句中调用了此函数。

我现在唯一的解决方案是将这个内联函数变成一个多语句函数并使用“OPTION (MAXRECURSION 2000);”。但出于性能原因,我宁愿避免使用此选项。 ¿ 还有其他选择吗?

感谢您的帮助。

【问题讨论】:

您必须在最后一个查询中使用OPTION (MAXRECURSION ...)。例如,我得到了带有递归 cte 的函数,我在另一个 cte 中运行这个函数,然后从中选择。我将在最后一个 SELECT 中使用 OPTION (MAXRECURSION ...) 【参考方案1】:

尝试在底部添加OPTION (MAXRECURSION 0) 或递归限制,如下所示。

您还可以使用Calendar table 来避免所有这些计算,从而提供您需要的输出..

我的数据库中填充了一个日历表,输出很容易计算,如下所示..我建议使用一个表而不是重复计算

select distinct month,year from dbo.calendar
where dAte>=getdate()-200 and date<=getdate()

如果您想使用递归选项,请添加option(recursion),如下所示

--这不适用于内联表值函数,请参见下面的演示 更改函数 [dbo].[fnYearMonth] ( @初始日期时间, @最终日期时间 ) 回报表 作为 返回 日期范围为 ( 选择@Initial 作为统计日期 联合所有 选择 dateadd(月, 1, StatDate) 从日期范围 其中 dateadd(month, 1, StatDate)

更新: MAX Recursion 选项不适用于内联表值函数,它仅适用于多表值函数..

演示:

alter function 
dbo.getnum_test
(
@n int
)
returns table
as return
With cte as
(
select @n as n
union all
select @n+1
from cte
)

select * from cte
where  n<1000
option (maxrecursion 0)

alter function dbo.itvftest
(
@n int
)
returns
@numbers table
(
n int
)
as 
begin

With cte as
(
select @n as n
union all
select n+1
from cte
where cte.n<10000
)
Insert into @numbers
select * from cte
where  n<1000
option (maxrecursion 0)

return
end

【讨论】:

创建一个插入 100(年)* 365(天)= 36500 行的日期表是个好主意吗?我认为这些行太多了。而第二种选择是不可能的。在内联函数中,OPTION 语句不可用。 sql management studio 给出语法错误。 我认为创建表是个好主意,我已经尝试使用递归 cte,让我尝试使用内联函数并更新问题 @ajmena 40k 行 int 值没什么。而且从表中读取数据会比不断执行函数要快。 似乎只支持多表值函数,我只会选择表选项,因为它可以在除此之外的许多情况下为您提供帮助 @ajmena 日期表(和时间表)是必经之路。 brentozar.com/archive/2014/12/simply-must-date-table-video

以上是关于TSQL:避免内联函数中的 MAXRECURSION 限制的主要内容,如果未能解决你的问题,请参考以下文章

避免 if 语句的内联函数指针

TSQL IVF 导致 ASP.net 应用程序超时

inline内联函数

C++基础--inline

什么是 tsql 窗口函数中的“窗口描述符”

如何避免在 .where() 函数中使用 IF-Else 并使用内联 if 条件?