简体   繁体   English

关于WITH RECURSIVE查询Postgres的可能解释

[英]Possible explanation on WITH RECURSIVE Query Postgres

I have been reading around With Query in Postgres. 我一直在阅读Postgres中的With Query。 And this is what I'm surprised with 这就是我很惊讶的地方

WITH RECURSIVE t(n) AS (
    VALUES (1)
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

I'm not able to understand how does the evaluation of the query work. 我不明白查询的评估如何工作。

  • t(n) it sound like a function with a parameter. t(n)听起来像是带有参数的函数。 how does the value of n is passed. n的值如何传递。

Any insight on how the break down happen of the recursive statement in SQL. 关于SQL递归语句如何分解的任何见解。

This is called a common table expression and is a way of expressing a recursive query in SQL: 这称为公用表表达式,是在SQL中表示递归查询的一种方式:

t(n) defines the name of the CTE as t , with a single column named n . t(n)将CTE的名称定义为t ,其中有一列称为n It's similar to an alias for a derived table: 它类似于派生表的别名:

select ... 
from (
  ...
) as t(n);

The recursion starts with the value 1 (that's the values (1) part) and then recursively adds one to it until the 99 is reached. 递归以值1(即values (1)一部分)开始,然后递归地将values (1) ,直到达到99。 So it generates the numbers from 1 to 99. Then final query then sums up all those numbers. 因此它将生成从1到99的数字。然后最终查询将所有这些数字相加。

n is a column name, not a "variable" and the "assignment" happens in the same way as any data retrieval. n是列名, 而不是 “变量”,并且“赋值”的发生方式与任何数据检索相同。

WITH RECURSIVE t(n) AS (
    VALUES (1) --<< this is the recursion "root"
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100 --<< this is the "recursive part"
)
SELECT sum(n) FROM t;

If you "unroll" the recursion (which in fact is an iteration) then you'd wind up with something like this: 如果您“展开”递归(实际上是一个迭代),那么您将得到如下结果:

select x.n + 1
from (
  select x.n + 1
  from (
    select x.n + 1
    from (
      select x.n + 1
      from (
         values (1)
      ) as x(n) 
    ) as x(n)
  ) as x(n)
) as x(n)

More details in the manual: 手册中的更多详细信息:
https://www.postgresql.org/docs/current/static/queries-with.html https://www.postgresql.org/docs/current/static/queries-with.html

If you are looking for how it is evaluated, the recursion occurs in two phases. 如果您正在寻找评估方式,则递归分为两个阶段。

  1. The root is executed once. 根执行一次。
  2. The recursive part is executed until no rows are returned. 递归部分一直执行到没有行返回为止。 The documentation is a little vague on that point. 关于这一点,文档有点模糊。

Now, normally in databases, we think of "function" in a different way than we think of them when we do imperative programming. 现在,通常在数据库中,我们对“功能”的思考方式与我们进行命令式编程时所想到的方式不同。 In database terms, the best way to think of a function is "a correspondence where for every domain value you have exactly one corresponding value." 用数据库术语来说,想到一个函数的最佳方法是“一种对应关系,对于每个域值,您都具有一个对应的值。” So one of the immediate challenges is to stop thinking in terms of programming functions. 因此,当前的挑战之一是停止就编程功能进行思考。 Even user-defined functions are best thought about in this other way since it avoids a lot of potential nastiness regarding the intersection of running the query and the query planner... So it may look like a function but that is not correct. 甚至用户定义的函数也最好用这种其他方式来考虑,因为它避免了在运行查询和查询计划程序的交集方面的许多潜在麻烦。因此,它看起来像一个函数,但这是不正确的。

Instead the WITH clause uses a different, almost inverse notation. 相反,WITH子句使用不同的,几乎相反的符号。 Here you have the set name t , followed (optionally in this case) by the tuple structure (n) . 在这里,您具有集合名称t ,后跟(在这种情况下为可选)元组结构(n) So this is not a function with a parameter, but a relation with a structure. 因此,这不是具有参数的函数,而是与结构的关系。

So how this breaks down: 因此,如何分解:

SELECT 1 as n where n < 100
UNION ALL
SELECT n + 1 FROM (SELECT 1 as n) where n < 100
UNION ALL
SELECT n + 1 FROM (SELECT n + 1 FROM (SELECT 1 as n)) where n < 100

Of course that is a simplification because internally we keep track of the cte state and keep joining against the last iteration, so in practice these get folded back to near linear complexity (while the above diagram would suggest much worse performance than that). 当然,这是一个简化,因为在内部我们会跟踪cte状态并保持对最后一次迭代的参与,因此在实践中,它们会折回到接近线性的复杂度(而上图显示的性能要差得多)。

So in reality you get something more like: 因此,实际上您会得到更多类似的信息:

 SELECT 1 as n where 1 < 100
 UNION ALL
 SELECT 1 + 1 as n where 1 + 1 < 100
 UNION ALL
 SELECT 2 + 1 AS n WHERE 2 + 1 < 100
 ...

In essence the previous values carry over. 本质上,以前的值会保留下来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM