关于 WITH RECURSIVE Query Postgres 的可能解释
Possible explanation on WITH RECURSIVE Query Postgres
我一直在阅读 Postgres 中的 With Query。这就是我感到惊讶的地方
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;
我无法理解查询的评估是如何工作的。
- t(n) 听起来像是带参数的函数。 n的值是如何传递的。
关于 SQL 中的递归语句如何发生故障的任何见解。
这称为通用 table 表达式,是 SQL 中表达递归查询的一种方式:
t(n)
将 CTE 的名称定义为 t
,其中包含一个名为 n
的列。它类似于派生 table:
的别名
select ...
from (
...
) <b><i>as t(n)</i></b>;
递归从值 1(即 values (1)
部分)开始,然后递归地对其加一,直到达到 99。所以它生成从 1 到 99 的数字。然后最终查询然后总结所有这些数字。
n
是列名,不是,"variable" 并且 "assignment" 的发生方式与任何数据检索相同。
WITH RECURSIVE t(n) AS (
VALUES (1) --<b><< this is the recursion "root"</b>
UNION ALL
SELECT n+1 FROM t WHERE n < 100 --<b><< this is the "recursive part"</b>
)
SELECT sum(n) FROM t;
如果你 "unroll" 递归(实际上是迭代)那么你会得到这样的结果:
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)
手册中的更多详细信息:
https://www.postgresql.org/docs/current/static/queries-with.html
如果您正在寻找它的计算方式,递归分两个阶段进行。
- 根执行一次。
- 执行递归部分,直到没有返回行。文档在这一点上有点含糊。
现在,通常在数据库中,我们考虑 "function" 的方式与我们在进行命令式编程时考虑的方式不同。在数据库方面,思考函数的最佳方式是 "a correspondence where for every domain value you have exactly one corresponding value." 因此,直接的挑战之一是停止从编程函数的角度思考。即使是用户定义的函数也最好以这种方式考虑,因为它避免了很多关于 运行 查询和查询计划器的交集的潜在麻烦......所以它可能看起来像一个函数,但事实并非如此正确。
相反,WITH 子句使用不同的、几乎相反的表示法。这里有集合名称 t
,后跟(在本例中为可选)元组结构 (n)
。所以这不是一个有参数的函数,而是一个结构体的关系。
那么这是如何分解的:
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
当然这是一种简化,因为在内部我们会跟踪 cte 状态并继续加入最后一次迭代,所以在实践中这些会折回到接近线性的复杂度(虽然上图表明性能比那个)。
所以实际上你得到的更像:
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
...
本质上,以前的值会沿用。
我一直在阅读 Postgres 中的 With Query。这就是我感到惊讶的地方
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;
我无法理解查询的评估是如何工作的。
- t(n) 听起来像是带参数的函数。 n的值是如何传递的。
关于 SQL 中的递归语句如何发生故障的任何见解。
这称为通用 table 表达式,是 SQL 中表达递归查询的一种方式:
t(n)
将 CTE 的名称定义为 t
,其中包含一个名为 n
的列。它类似于派生 table:
select ...
from (
...
) <b><i>as t(n)</i></b>;
递归从值 1(即 values (1)
部分)开始,然后递归地对其加一,直到达到 99。所以它生成从 1 到 99 的数字。然后最终查询然后总结所有这些数字。
n
是列名,不是,"variable" 并且 "assignment" 的发生方式与任何数据检索相同。
WITH RECURSIVE t(n) AS (
VALUES (1) --<b><< this is the recursion "root"</b>
UNION ALL
SELECT n+1 FROM t WHERE n < 100 --<b><< this is the "recursive part"</b>
)
SELECT sum(n) FROM t;
如果你 "unroll" 递归(实际上是迭代)那么你会得到这样的结果:
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)
手册中的更多详细信息:
https://www.postgresql.org/docs/current/static/queries-with.html
如果您正在寻找它的计算方式,递归分两个阶段进行。
- 根执行一次。
- 执行递归部分,直到没有返回行。文档在这一点上有点含糊。
现在,通常在数据库中,我们考虑 "function" 的方式与我们在进行命令式编程时考虑的方式不同。在数据库方面,思考函数的最佳方式是 "a correspondence where for every domain value you have exactly one corresponding value." 因此,直接的挑战之一是停止从编程函数的角度思考。即使是用户定义的函数也最好以这种方式考虑,因为它避免了很多关于 运行 查询和查询计划器的交集的潜在麻烦......所以它可能看起来像一个函数,但事实并非如此正确。
相反,WITH 子句使用不同的、几乎相反的表示法。这里有集合名称 t
,后跟(在本例中为可选)元组结构 (n)
。所以这不是一个有参数的函数,而是一个结构体的关系。
那么这是如何分解的:
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
当然这是一种简化,因为在内部我们会跟踪 cte 状态并继续加入最后一次迭代,所以在实践中这些会折回到接近线性的复杂度(虽然上图表明性能比那个)。
所以实际上你得到的更像:
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
...
本质上,以前的值会沿用。