WITH 查询是否存储引用表的结果 | Postgres SQL
does WITH query store the results of referred tables | Postgres SQL
以下是查询结构
WITH TAB1 AS ( SELECT * FROM HUGE_TABLE_1 WHERE id='something' ),
TAB2 AS ( SELECT * FROM HUGE_TABLE_2 WHERE id='something' LEFT JOIN TAB1 ON TAB1.id=TAB2.id )
TAB3 AS ( SELECT * FROM HUGE_TABLE_3 WHERE id='something' LEFT JOIN TAB2 ON TAB1.id=TAB2.id )
SELECT JSON_BUILD_OBJECT( ... , 'TAB2', JSON2 ) AS JSON1, id FROM TAB1 GROUP BY FK_ID LEFT JOIN
( SELECT JSON_BUILD_OBJECT( ... , 'TAB3', JSON3 ) AS JSON2, id FROM TAB3 GROUP BY FK_ID LEFT JOIN
( SELECT ROW_TO_JSON(TAB3.*) AS JSON3, id FROM TAB3 GROUP BY FK_ID ) AS JOIN2 ... ) AS JOIN1 ...
在上面的示例查询中,表TAB1和TAB2被多次引用,那么TAB1或TAB2查询是否会在每次被引用或结果存储到Postgres时执行?
通常,CTE 总是在 Postgres 11 或更早版本中具体化。
或者如果它们在 Postgres 12 或更高版本中被重复引用。 The manual:
A useful property of WITH
queries is that they are normally
evaluated only once per execution of the parent query, even if they
are referred to more than once by the parent query or sibling WITH
queries.
此外,您可以在 Postgres 12 或更高版本中使用子句 MATERIALIZED
或 NOT MATERIALIZED
强制执行一种或另一种行为。
您可以使用EXPLAIN
查看实际的查询计划。任何提及 CTE Scan
都意味着所涉及的 CTE 已经具体化。
另请注意,带有 SELECT
且未被引用的 CTE 根本不会执行。
您的代码示例在逻辑和句法上都是胡说八道。所以很难理解它。很有可能,此查询根本不需要任何 CTE。 CTE 总是会增加开销。 (在 Postgres 12 或更高版本中更少。)他们仅在物化保存重复工作时付费。 (或者,如果它强制执行不同的查询计划作为副作用。)所以只在需要时使用 CTE,或者当您不关心性能而更喜欢语法时。
以下是查询结构
WITH TAB1 AS ( SELECT * FROM HUGE_TABLE_1 WHERE id='something' ),
TAB2 AS ( SELECT * FROM HUGE_TABLE_2 WHERE id='something' LEFT JOIN TAB1 ON TAB1.id=TAB2.id )
TAB3 AS ( SELECT * FROM HUGE_TABLE_3 WHERE id='something' LEFT JOIN TAB2 ON TAB1.id=TAB2.id )
SELECT JSON_BUILD_OBJECT( ... , 'TAB2', JSON2 ) AS JSON1, id FROM TAB1 GROUP BY FK_ID LEFT JOIN
( SELECT JSON_BUILD_OBJECT( ... , 'TAB3', JSON3 ) AS JSON2, id FROM TAB3 GROUP BY FK_ID LEFT JOIN
( SELECT ROW_TO_JSON(TAB3.*) AS JSON3, id FROM TAB3 GROUP BY FK_ID ) AS JOIN2 ... ) AS JOIN1 ...
在上面的示例查询中,表TAB1和TAB2被多次引用,那么TAB1或TAB2查询是否会在每次被引用或结果存储到Postgres时执行?
通常,CTE 总是在 Postgres 11 或更早版本中具体化。
或者如果它们在 Postgres 12 或更高版本中被重复引用。 The manual:
A useful property of
WITH
queries is that they are normally evaluated only once per execution of the parent query, even if they are referred to more than once by the parent query or siblingWITH
queries.
此外,您可以在 Postgres 12 或更高版本中使用子句 MATERIALIZED
或 NOT MATERIALIZED
强制执行一种或另一种行为。
您可以使用EXPLAIN
查看实际的查询计划。任何提及 CTE Scan
都意味着所涉及的 CTE 已经具体化。
另请注意,带有 SELECT
且未被引用的 CTE 根本不会执行。
您的代码示例在逻辑和句法上都是胡说八道。所以很难理解它。很有可能,此查询根本不需要任何 CTE。 CTE 总是会增加开销。 (在 Postgres 12 或更高版本中更少。)他们仅在物化保存重复工作时付费。 (或者,如果它强制执行不同的查询计划作为副作用。)所以只在需要时使用 CTE,或者当您不关心性能而更喜欢语法时。