七月 3, 2025
摘要:在本教程中,您将学习如何在 PostgreSQL 中强制执行连接顺序。
目录
初始设置
让我们首先创建一些表:
CREATE TABLE x1 (id int);
CREATE TABLE x2 (id int);
CREATE TABLE x3 (id int);
CREATE TABLE x4 (id int);
CREATE TABLE x5 (id int);
好的,我们有了 5 个表可以作为示例数据结构。
在 PostgreSQL 中连接表
下面的查询显示了使用我们刚刚创建的表的简单连接:
explain (timing, analyze) SELECT *
FROM x1 JOIN x2 ON (x1.id = x2.id)
JOIN x3 ON (x2.id = x3.id)
JOIN x4 ON (x3.id = x4.id)
JOIN x5 ON (x4.id = x5.id);
...
Planning Time: 0.297 ms
Execution Time: 0.043 ms
这里的重要观察是什么?让我们来看看规划时间。PostgreSQL 需要 0.297 毫秒来找到运行查询的最佳执行计划(即执行策略)。随之而来的问题是:规划器在哪里需要时间来规划查询?事实上,即使使用如上所示的显式连接,PostgreSQL 也会隐式地连接这些表,并确定最佳连接顺序。这在现实情况中意味着什么?让我们考虑一个连接 “a join b join c”:即使我们编写一个 SQL 来连接 a 到 b,优化器仍可能决定投票支持“c join a join b”,因为它可以保证相同的结果。为什么这会如此重要?因为它提供了很大的效率。让优化器决定最佳连接顺序是一项重要的内部优化。
然而,这里的规划时间值得关注:特别是如果涉及很多个表(10 个以上?)。
控制 SQL 中的连接行为
如果规划时间是个问题,我们可以强制 PostgreSQL 使用我们想要的连接顺序。控制此行为的参数是 join_collapse_limit。它是什么意思呢?基本上,它控制隐式规划的显式连接的数量。换句话说:PostgreSQL 可以优化多少个显式连接。
如果我们将此变量设置为 1,则意味着我们强制 PostgreSQL 使用我们选择的连接顺序:
SET join_collapse_limit TO 1;
explain (timing, analyze) SELECT *
FROM x1 JOIN x2 ON (x1.id = x2.id)
JOIN x3 ON (x2.id = x3.id)
JOIN x4 ON (x3.id = x4.id)
JOIN x5 ON (x4.id = x5.id);
...
Planning Time: 0.069 ms
Execution Time: 0.046 ms
真正值得注意的是规划速度的显著提升。我们可以看到加速了 4 倍之高。
不过,还是要提醒大家:优化器尝试重构连接顺序是有原因的。如果查询的开销比我们在本例中看到的要大,那么投入更多时间创建计划就显得尤为重要。换句话说:除非最终用户完全了解情况,否则更改该参数可能会适得其反。因此,我们建议在更改该设置之前,使用真实数据和真实工作负载测试您的查询和所有设置。通常,只更改单个查询的参数,并为所有其他操作在 postgresql.conf 中保留参数的默认值,也是有益的。