我的应用程序当前使用 PostgreSQL 11.6。今天,我在虚拟机上测试了 PostgreSQL 12.1,结果令人震惊:一个重要查询在版本 11(同一虚拟机)上需要 100 毫秒,现在在 Postgres 12 上只需要大约 36 秒。这慢了 300 多倍。
我怀疑 CTE 的新处理方式,即MATERIALIZED,NOT MATERIALIZED是造成这种情况的原因。
如果我将每个 CTE 更改为MATERIALIZED,查询时间将从 36 秒减少到 6 秒。明显好一些,但仍然比版本 11 慢 50 倍以上。
如果我没猜错的话,在 PostgreSQL 12 中你有两个替代选项:
MATERIALIZEDCTE 只执行一次,但你失去了索引的好处NOT MATERIALIZED索引的好处,但每次访问其结果时都会执行您的 CTE。那是对的吗?
是否有任何技巧,例如返回 Postgres 11 行为的特殊设置?或者是处理此问题的唯一方法,手动评估每个 CTE 是否MATERIALIZED更好NOT MATERIALIZED?
我想,很多时候并不清楚哪种方式更好。我的应用程序包含数百个 CTE,其中许多都执行表查询和昂贵的函数调用(文档中的示例,他们说这NOT MATERIALIZED更好)。
编辑: 我检查过的内容以使结果具有可比性:
vacuum analyze结果EXPLAIN ANALYZE …
我一直在阅读有关 PostgreSQL 的新 CTE 功能 - MATERIALIZED 或 NOT MATERIALIZED 关键字 - 它可以在某些情况下提供额外的优化机会,前提是这样做是安全的。对此PostgreSQL 更新的评论如下:
...用户可以通过指定 MATERIALIZED 强制旧行为 [LESS OPTIMIZED];当查询故意使用WITH作为优化栅栏以防止计划选择不当时,这主要有用。
我一直想知道,考虑到在某种情况下使用 CTE 优化(不是 MATERIALIZED 关键字)是安全的,在这种情况下,优化程度较低的“MATERIALIZED”关键字可以“防止错误的计划选择”,如引用所述或提供更好的计划?
最后一点,这是/sf/ask/4249081091/上的问题的副本。我得到的建议是这个问题更适合这个社区,因此在这里重新发布。
我将 Postgres 13.3 与内部和外部查询一起使用,它们都只产生一行(只是一些关于行数的统计数据)。
我不明白为什么下面的 Query2 比 Query1 慢得多。它们基本上应该几乎完全相同,最多可能只有几毫秒的差异......
WITH t1 AS (
SELECT
(SELECT COUNT(*) FROM racing.all_computable_xformula_bday_combos) AS all_count,
(SELECT COUNT(*) FROM racing.xday_todo_all) AS todo_count,
(SELECT COUNT(*) FROM racing.xday) AS xday_row_count
OFFSET 0 -- this is to prevent inlining
)
SELECT
t1.all_count,
t1.all_count-t1.todo_count AS done_count,
t1.todo_count,
t1.xday_row_count
FROM t1;
Run Code Online (Sandbox Code Playgroud)
我只添加了一行:
WITH t1 AS (
SELECT
(SELECT COUNT(*) FROM racing.all_computable_xformula_bday_combos) AS all_count,
(SELECT COUNT(*) FROM racing.xday_todo_all) AS todo_count,
(SELECT COUNT(*) …Run Code Online (Sandbox Code Playgroud)