首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >国人提交PG 19“JOIN+聚合场景”优化补丁

国人提交PG 19“JOIN+聚合场景”优化补丁

作者头像
用户4035096
发布2026-07-09 19:30:20
发布2026-07-09 19:30:20
80
举报

PostgreSQL 19 preview - 国人提交“JOIN+聚合场景”优化补丁

前几天读到一篇关于"先groupby再JOIN"的数据库论文:

  • 《AI论文解读 | Accelerating Queries With Groupby And Join By Group Join》

没想到今天在PG社区就看到类似场景的优化补丁了: Implement Eager Aggregation

这个PATCH 由 Antonin Houska 在 2017 年提出原型. 2025 Richard Guo(郭峰@OpenPie) 重构并重写了大部分代码,解决了正确性、性能和集成问题。经过多轮社区评审(Robert Haas、Tom Lane 等核心开发者参与),最终合并。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=8e11859102f947e6145acdd809e5cdcdfbe90fa5

下面来看一下这个patch的详细解读 :

这个 PostgreSQL 补丁 “Implement Eager Aggregation”(实现“急切聚合”)由 Richard Guo 提交,是对查询优化器的一项重要增强。它引入了一种称为 Eager Aggregation(急切聚合) 的优化技术,旨在通过在连接(JOIN)之前提前执行部分聚合,减少中间数据量,从而提升查询性能。

下面从多个维度详细讲解该补丁的核心思想、实现机制、限制条件和意义。

一、什么是 Eager Aggregation?

Eager Aggregation 是一种查询优化策略:

在执行 JOIN 之前,尽可能早地对某个表或子查询进行部分聚合(partial aggregation),然后再参与后续的连接操作,最终在顶层完成完整的聚合。

举个例子:

原始查询:

代码语言:javascript
复制
SELECT a.x, SUM(b.y)  
FROM a  
JOIN b ON a.id = b.a_id  
GROUP BY a.x;  

传统执行计划:

  1. 先对 ab 做完整连接(可能产生大量中间行);
  2. 再按 a.x 分组并聚合 SUM(b.y)

启用 Eager Aggregation 后的优化计划:

  1. 先对 bb.a_id 做部分聚合(例如 SUM(b.y) GROUP BY b.a_id);
  2. 再将聚合后的 ba 连接;
  3. 最后按 a.x 做最终聚合(可能只需重分组,无需再处理大量原始行)。

效果:如果 b 中每个 a_id 对应大量行,提前聚合可显著减少连接输入规模。

二、为什么需要这个优化?

PostgreSQL 原有的优化器架构存在一个结构性限制

扫描/连接规划阶段(scan/join planning)与聚合阶段是分离的。 聚合信息(如 GROUP BY、HAVING、聚合函数)在构建连接树时不可见,因此无法在连接前考虑是否可以提前聚合。

这导致优化器错失了通过提前聚合减少中间数据量的机会

Eager Aggregation 通过在规划早期收集聚合上下文,并在连接规划阶段动态生成“已分组的关系(grouped relation)”,打破了这一限制。

三、关键技术实现

1. 聚合信息提前收集
  • PlannerInfo 中记录:
    • 聚合函数(来自 SELECT 和 HAVING)
    • GROUP BY 表达式
    • 分组键(grouping keys)

这些信息在后续的连接规划中用于判断是否可应用 Eager Aggregation。

2. 引入“Grouped Relation”概念
  • 对于某个基表或连接结果,如果满足条件,会创建一个新的 RelOptInfo,称为 grouped relation
  • 它代表“已经按某些键部分聚合过”的版本。
  • 为这个 grouped relation 生成新的执行路径(paths):
    • Sorted Partial Aggregation Path(排序后聚合)
    • Hashed Partial Aggregation Path(哈希聚合)

为控制规划开销,只对最便宜的或已排序的非分组路径生成分组路径。

3. 分组路径的生成方式
  • 方式一:对单个基表/子查询直接做部分聚合。
  • 方式二:将一个 grouped relation 与一个 non-grouped relation 进行连接(产生新的 grouped relation)。
  • 不支持:两个 grouped relations 之间的连接(当前版本限制)。
4. 确保正确性的关键:扩展分组键

当对某个表做部分聚合时,必须将该表中用于后续 JOIN 的所有列加入分组键

例如:

代码语言:javascript
复制
... FROM a JOIN b ON a.id = b.a_id AND a.status = b.status ...  

若对 b 做部分聚合,则分组键必须包含 b.a_idb.status,否则:

  • 同一组内的多行可能在连接时匹配到不同的 a 行;
  • 导致聚合结果错误(“destiny” 不一致)。

补丁通过分析上层 JOIN 条件,自动将相关列加入 partial GROUP BY。

5. 限制:不能用于 OUTER JOIN 的 nullable 侧
  • 如果某表在 LEFT/RIGHT/FULL OUTER JOIN 的 nullable 一侧(如 LEFT JOIN 的右表),不能对其做 Eager Aggregation
  • 原因:OUTER JOIN 会生成 NULL 扩展行,这些行在顶层聚合时会影响结果(如 COUNT(*) 会包含 NULL 行)。
  • 若提前聚合,这些 NULL 行尚未生成,会导致结果错误。

四、规划策略与性能权衡

  • 保守策略:只在“能显著减少行数”的最低层级应用 Eager Aggregation。
    • 避免生成过多备选路径,控制规划时间。
    • 确保同一 grouped relation 的所有路径产生相同的结果集(满足优化器假设)。
  • 最终,顶层的 grouped relation 会生成 finalized paths,与传统路径一起参与 cost 比较,选择最优计划。

五、历史背景与贡献

  • 最初由 Antonin Houska 在 2017 年提出原型。
  • Richard Guo 重构并重写了大部分代码,解决了正确性、性能和集成问题。
  • 经过多轮社区评审(Robert Haas、Tom Lane 等核心开发者参与),最终合并。

六、意义与影响

性能提升:对“大表连接后聚合”的场景(如星型模型、OLAP 查询)有显著加速。 ✅ 架构改进:打破 scan/join 与 aggregation 的隔离,为未来更多聚合感知优化铺路。 ⚠️ 谨慎启用:通过 cost 模型自动决策,无需用户干预,保证安全性和通用性。

总结

特性

说明

目标

减少 JOIN 前的数据量,提升聚合查询性能

核心机制

在连接规划阶段生成“部分聚合”的 grouped relation

关键保障

扩展分组键以保持 JOIN 语义正确;禁止用于 OUTER JOIN nullable 侧

规划开销控制

仅在收益显著时应用;限制路径生成数量

用户透明

自动启用,无需语法或配置变更

这项补丁代表了 PostgreSQL 优化器向更智能、更上下文感知方向迈出的重要一步,尤其利好数据分析类负载。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-10-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 digoal德哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PostgreSQL 19 preview - 国人提交“JOIN+聚合场景”优化补丁
    • 一、什么是 Eager Aggregation?
      • 举个例子:
    • 二、为什么需要这个优化?
    • 三、关键技术实现
      • 1. 聚合信息提前收集
      • 2. 引入“Grouped Relation”概念
      • 3. 分组路径的生成方式
      • 4. 确保正确性的关键:扩展分组键
      • 5. 限制:不能用于 OUTER JOIN 的 nullable 侧
    • 四、规划策略与性能权衡
    • 五、历史背景与贡献
    • 六、意义与影响
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档