【问题标题】:Joining too many tables makes Postgres query extremely slow加入太多的表会使 Postgres 查询非常慢
【发布时间】:2022-12-19 22:59:15
【问题描述】:

我一直在尝试优化 Postgres 12 上的这个简单查询,该查询将多个表连接到一个基本关系。它们每个都有一对一的关系,并且有 10,000 到 1,000 万行。

   SELECT *
     FROM base
LEFT JOIN t1 ON t1.id = base.t1_id
LEFT JOIN t2 ON t2.id = base.t2_id
LEFT JOIN t3 ON t3.id = base.t3_id
LEFT JOIN t4 ON t4.id = base.t4_id
LEFT JOIN t5 ON t5.id = base.t5_id
LEFT JOIN t6 ON t6.id = base.t6_id
LEFT JOIN t7 ON t7.id = base.t7_id
LEFT JOIN t8 ON t8.id = base.t8_id
LEFT JOIN t9 ON t9.id = base.t9_id

(实际关系比这复杂一点,但为了演示目的,这很好)

我注意到当我只执行 SELECT base.id 时查询仍然很慢,这看起来很奇怪,因为查询规划器应该知道连接是不必要的并且不应该影响性能。

然后我注意到 8 似乎是某种神奇的数字。如果我删除任何一个连接,查询时间将从 500 毫秒变为 1 毫秒。通过 EXPLAIN,我能够看到 Postgres 在连接 8 个表时只进行索引扫描,但是对于 9 个表,它开始进行顺序扫描。

即使我只执行SELECT base.id,表的数量也会以某种方式阻碍查询规划器。

【问题讨论】:

    标签: postgresql join query-optimization


    【解决方案1】:

    我们终于发现在postgres中确实有一个名为join_collapse_limit的配置设置,默认设置为8。

    https://www.postgresql.org/docs/current/runtime-config-query.html

    每当生成不超过这么多项的列表时,规划器会将显式 JOIN 构造(FULL JOIN 除外)重写为 FROM 项列表。较小的值会减少计划时间,但可能会产生较差的查询计划。默认情况下,此变量设置为与 from_collapse_limit 相同,适用于大多数用途。将其设置为 1 可防止对显式 JOIN 进行任何重新排序。因此,查询中指定的显式连接顺序将是连接关系的实际顺序。因为查询规划器并不总是选择最佳连接顺序,所以高级用户可以选择暂时将此变量设置为 1,然后明确指定他们想要的连接顺序。

    阅读this article后,我们决定增加限制,以及其他值,如from_collapse_limitgeco_threshold。请注意,查询计划时间会随着连接数量呈指数增长,因此存在限制是有原因的,不应随意增加。

    【讨论】:

      猜你喜欢
      • 2021-12-18
      • 2017-01-07
      • 2016-12-12
      • 2021-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多