更改maxrecursion的系统范围默认值


12

如何更改系统范围的默认值MAXRECURSION

默认情况下为100,但是我需要将其增加到1000。

我无法使用查询提示,因为我使用的程序会接受我的查询并为我执行查询,但是不幸的是,我无法解决此限制。

但是,我确实对服务器实例具有管理员权限。我在服务器方面进行了摸索,但没有看到与查询选项或递归相关的任何信息。我假设有是一个某处在那里我可以更新系统范围内的默认。

有任何想法吗?


3
我只是想检查一下您是否理解100个限制仅适用于视图和函数,并且您可以使用存储过程并在那里局部覆盖?是否有使用功能的特别需要?由于递归效率很低,因此我也建议仅遍历层次结构一次并将输出存储在表中。然后,您可以创建一个引用该表的函数。你怎么看?
wBob

Answers:


10

如果查询的形状相同,则可以使用一个或多个计划指南来添加所需的maxrecursion提示。

弄清楚它们是有诀窍的。如果您在问题中添加特定的查询详细信息,我们可能会为您解决。通常,您将跟踪实际击中服务器的SQL,或者使用内置过程sys.sp_get_query_template获取参数化形式,然后创建TEMPLATE和/或OBJECT / SQL计划指南。

请参阅文档以获取更多信息:

每当应用程序代码更改以及SQL Server修补或升级时,都需要重新验证计划指南。这应该只是正常测试周期的一部分。

请注意,如果被引导的语句引用了临时表,则使用sys.fn_validate_plan_guide进行计划指南的验证可能会错误地报告失败。看到这个问题:

使用fn_validate_plan_guide进行计划指南验证会产生误报

计划指南成功计划指南不成功的探查和扩展事件类也可以用来监测计划指南应用程序。

在实现产品改进建议之前,史蒂夫·卡斯(Steve Kass)的视图和UDF的“允许MAXRECURSION”极限值不为100时, Connect已被淘汰。如果您现在想使用Microsoft,请参阅SQL Server帮助和反馈中的选项。


这令人沮丧,并且没有回答这个问题,反而把我们埋在了文档的兔子洞中。EF Core(典型的ORM)会为您生成查询,即使您为其提供了原始SQL语句,它也会将其包装在父选择中,使用EF Core的任何人都会遇到此问题。您的解决方案是“计划您的查询”。
战争

@War这是我可以通过提供的详细信息对这个特定问题给出的最佳答案。我知道添加最大递归提示的唯一方法是通过SQL Server(称为“计划指南”)进行,这与“计划查询”无关。如果您有自己的特定问题,请以最小的可复制示例单独提问。
保罗·怀特9

9

如果您必须使用某个函数(暗示您的ETL工具的局限性),则可以将其指定OPTION为多语句表值函数的一部分,例如:

CREATE FUNCTION dbo.udf_MyFunction ( @StartID INT ) 
RETURNS @tv TABLE
(
id INT
)
AS
BEGIN

    WITH Episodes( xlevel, PersonID, EventID, EpisodeID, StartDT, EndDT ) AS (
    -- Anchor case - the first EventID for each person.
    SELECT 1 AS xlevel, PersonID, EventID, @StartID, StartDT, EndDT 
    FROM dbo.EventTable
    WHERE EventID = @StartID

    UNION ALL

    SELECT xlevel + 1, et.PersonID, et.EventID, c.EventID + 1, et.StartDT, et.EndDT
    FROM Episodes c
        INNER JOIN dbo.EventTable et ON c.PersonID = et.PersonID
            AND et.EventID = c.EventID + 1
    --WHERE c.EventID <= (@StartID + 99)
    )
    INSERT INTO @tv
    SELECT PersonID
    FROM Episodes
    OPTION ( MAXRECURSION 1000 )

    RETURN

END
GO

当您建议使用ETL工具时,将其包装在视图中时,这也对我有用。无法在整个系统范围内进行更改,但是由于递归效率低下,这可能是一件好事。OPTION如示例所示,您不能在内联表值函数的主体内指定查询提示(使用)。

考虑收到您的情节并将输出存储在关系表中时,更改流程以仅遍历层次结构一次。您可以使用存储的proc来执行此操作,因此不会遇到此限制。

我还认为您的代码中可能存在一个错误:如果您的CTE加入personId并在eventId上递归,则eventId 101会重复出现两次。可能我误解了您的代码,请告诉我您的想法。

高温超导


这不起作用,因为必须在语句级别应用“ OPTIONS”参数,并且所讨论的语句是对该函数的调用,这将返回异常。
战争

0

我从这个话题中得到启发。

这是我为解决问题所做的工作。

CREATE FUNCTION MySchema.udf_MyFunction(@StartID INT) 
RETURNS TABLE 
AS RETURN
WITH
Episodes(PersonID, EventID, EpisodeID, StartDT, EndDT) AS (
  -- Anchor case - the first EventID for each person.
  SELECT PersonID, EventID, @StartID, StartDT, EndDT 
  FROM MySchema.EventTable
  WHERE EventID = @StartID
UNION ALL
  SELECT
    ...
  WHERE
    EventID <= (@StartID + 99)
)
SELECT * FROM Episodes

然后,我像这样调用此函数:

WITH
Episodes AS (
  SELECT * FROM MySchema.udf_MyFunction(1)
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(101)
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(201)
-- ...
UNION ALL
  SELECT * FROM MySchema.udf_MyFunction(901)
)
SELECT * FROM Episodes

这样,我的CTE逻辑就不必重复了,而且我在性能方面不需要付出任何额外的费用。这样做很麻烦,但我可以接受。


3
我看不到这如何解决递归问题。该函数的调用不是递归的。
ypercubeᵀᴹ

@ypercubeᵀᴹ-CTE的递归位放在我省略号的位置-我的特定递归逻辑与该问题并不真正相关,但是您可以假定CTE实际上是递归的。在where省略号后子句防止太多递归从使用功能参数作为约束发生。我想在CTE定义之后应该有一个声明。我将添加。
carl.anderson '16

3
我非常了解CTE是递归的。问题是调用(函数调用)不是递归的。例如,以EventID=1(和101,201,... 901)为起点(行)调用函数。但是原始查询(如果以MAXRECURSION = 100000000运行)可能永远不会访问带有EventID=101(和201,..,901)的行。因此,这两个查询(原始查询和您的解决方案)可能返回不同的结果(第一个行中没有101,第二个行中是)!或者,它可以访问101,但步骤100之前,让您的解决方案将包括在结果两次行(再次不同)
ypercubeᵀᴹ

2
当然,除非数据是通过顺序EventID值(1,2,,3 ...,99,100,101,..)连接的。在这种情况下,您根本不需要递归CTE。
ypercubeᵀᴹ

这如何解决诸如...从给定DMS路径中获取树作为行集之类的未知深度问题?
战争
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.