首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Server如何知道在递归CTE中不执行第二次迭代/第一次递归的Anchor元素?

Server如何知道在递归CTE中不执行第二次迭代/第一次递归的Anchor元素?
EN

Database Administration用户
提问于 2023-02-14 19:40:57
回答 1查看 81关注 0票数 0

我一直在阅读CTE Recursion的内部工作原理,我仍然不确定SQL Server是如何在源代码中实现Anchor元素的,以及SQL Server查询执行引擎/查询优化器是如何解释这些指令集的。

为了遵循逻辑,我仔细阅读了以下文章:http://sqlchitchat.com/sqldev/tsql/recursive-cte/

让我们以上述文章中的示例1为例:https://github.com/dmincic/SQLCHITCHAT/blob/master/CTE/Sql/Example1_cteQuery.sql

代码语言:javascript
复制
DECLARE @EmpId INT = 3;

;WITH cte1 AS
(
    -- Anchor Element
    SELECT EmpId
          ,MgrId
    FROM dbo.Employees
    WHERE MgrId = @EmpId

    UNION ALL

    -- Recursive Element
    SELECT e.EmpId
          ,e.MgrId
    FROM dbo.Employees e
      INNER JOIN cte1 c
        ON e.MgrId = c.EmpId
)
-- Invoke CTE Recursion
SELECT cte1.EmpId
      ,cte1.MgrId
FROM cte1;

如果您向下滚动到本文的中间,它将讨论锚元素在第二次迭代/第一次递归中的作用:

第二个迭代begins.This是第一个递归。锚部分在第一次迭代中发挥了作用,从现在起只返回空集。但是,递归部分现在可以在内部联接操作符中引用它以前的结果(第一次迭代之后的cte1值)。表操作产生第二次迭代的结果,如下图所示。

图5:https://sqlchitchat.com/wp-content/uploads/2019/10/2nd_Iteration1.png

在图中,您可以看到为EmpId和MgrId绘制的空集(嗯,元组)。

然后我阅读了SQL递归实际上是如何工作的?,从所提供的答案来看,Anchor元素甚至没有为N+1迭代进行评估。

那么,是哪一个呢?QE/QO是在每次迭代中评估Anchor,还是在递归期间返回空元组,还是在递归过程中跳过Anchor,从而永远不会返回空元组?

为了澄清我的问题,下面是我要问的问题:底层代码是否类似于:

代码语言:javascript
复制
static void Main(string[] args)
{
    int Number = 0;
    long Result;

    // Anchor part
    Number = GetNumberFromProgramArguments();

    // Anchor part is only executed once

    // Recursive part
    Result = CalculateFactorial(Number);
}
public static long CalculateFactorial(int number)
{
    // Termination check
    if (number == 0)
        return 1;

    // Recursive call
    return number * CalculateFactorial(number - 1);
}

或者更像这样:

代码语言:javascript
复制
static void Main(string[] args)
{
    int Number = 0;
    long Result;
    int RecursionLevel = 0;

    // Recursive part
    Result = CalculateFactorial(Number, RecursionLevel);
}
public static long CalculateFactorial(int number, int recursionLevel)
{
   // Run Anchor part only if Recursion Level is 0
   if (recursionLevel == 0)
   
       // Anchor part
       number = GetNumberFromProgramArguments();
   
   // Termination check
   if (number == 0)
       return 1;

    // Increment recursion
    recursionLevel++;

    // Recursive call
    return number * CalculateFactorial(number - 1, recursionLevel);
}

这不是最好的例子,因为我一直在关注表格,而不是数字,但我希望你能理解我的观点。为什么文章指出在递归期间,Anchor作为一个空元组被评估和返回?这就是我在这里感到困惑的地方。这没有意义。SQL执行计划没有显示为N+1迭代计算的Anchor部分,只是第一次迭代。如果是这样的话,那么锚部分在递归期间将永远不会返回任何内容,因为执行永远不会到达代码的那个部分,甚至可以计算锚点。我不明白为什么图5显示在递归期间锚点被计算为空元组。它甚至不应该显示任何东西。

是的,我了解到,如果可以的话,递归正在抓住上一次迭代。但是,从图5和我引用的段落中,博客指出锚点执行每一次迭代,并返回递归部分的空元组,这在SQL执行计划中并不明显。“执行计划”显示“锚”一次又一次执行。你知道我为什么在这里搞不懂吗?

EN

回答 1

Database Administration用户

发布于 2023-02-14 20:28:42

您所指的锚部分将只进行一次评估。您可以将其与归纳证明中的基本情况进行比较。这可以用一个简单的例子来说明:

代码语言:javascript
复制
with t (n,origin) as ( 
  select 1, 'Anchor   '
  union all
  select n+1, 'Recursive'
  from t where n<10
)
select * from t;

n   origin
1   Anchor
2   Recursive
3   Recursive
4   Recursive
5   Recursive
6   Recursive
7   Recursive
8   Recursive
9   Recursive
10  Recursive

如果多次评估的锚部分将是结果的一部分,因为没有可以计算为false的谓词。

小提琴

票数 2
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/323511

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档