从 Postgres 11 升级到 Postgres 12 使某些查询速度慢了 300 倍,可能是由于新的 CTE 处理

cis*_*cis 6 cte upgrade postgresql-12 postgresql-performance

我的应用程序当前使用 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更好)。

编辑: 我检查过的内容以使结果具有可比性:

  • 同一虚拟机
  • 相同且非常小的数据集
  • 相同的 postgresql.conf
  • 重新索引
  • vacuum analyze

结果EXPLAIN ANALYZEPostgres 11 Postgres 12

cis*_*cis 3

正如我在另一个更具体的问题的答案中所指出的,原因是即时编译。

SET jit = false;解决了我的案例中的所有性能问题。