【Calcite 系列】深入理解 Calcite 的 AggregateValuesRule

AggregateValuesRule 处理的是 Aggregate 压在 Values 之上的极端小输入场景,尤其是空 Values 和"纯去重 aggregate"这两类情况。它不会试图通用执行所有聚合,而是专注做一些完全可以在优化阶段直接折叠的改写。本文结合源码实现,分析这条规则如何在空输入上直接构造聚合结果,以及它是怎样把 Aggregate(Values) 规约成去重后的 Values 的。

1. 规则要解决什么问题

有些查询在优化阶段就已经变成:

text 复制代码
Aggregate
  Values(...)

例如:

  • WHERE 1 = 0 之后的空输入;
  • IN (...) 常量列表展开后的 values;
  • 仅用 aggregate 去重的极小关系。

这时没必要等到执行期再跑真正的聚合算子。

2. 第一类场景:空 Values + 全局聚合

源码首先处理:

java 复制代码
aggregate.getGroupCount() == 0 && values.getTuples().isEmpty()

也就是 GROUP BY () 且输入为空。

这时它会直接按聚合函数种类构造结果字面量:

  • COUNT / SUM0 -> 0
  • MIN / MAX / SUM -> NULL

然后直接生成一个单行 Values 作为结果。

3. 为什么只支持这几类聚合

对于空输入,不同聚合函数的返回值语义并不统一。

源码只对以下几种做了明确支持:

  • COUNT
  • SUM0
  • MIN
  • MAX
  • SUM

其他未知聚合函数会直接退出,避免错误推断其空输入语义。

4. 第二类场景:Aggregate 只是做 DISTINCT

如果满足:

  1. Aggregate.isSimple(aggregate)
  2. aggCallList 为空;
  3. aggregate.getRowType().equals(values.getRowType())

说明这个 Aggregate 本质上只是对 Values 去重。

这时规则会直接:

java 复制代码
values.getTuples().stream().distinct()

把重复元组去掉,再生成一个新的 Values

5. 为什么要求 row type 相同

如果 aggregate 输出行类型和 values 输入行类型不一样,那么简单去重后直接返回 Values 可能会破坏 schema。

所以源码只在两者 row type 完全一致时,才把它规约成纯 Values

6. 这条规则为什么很有用

虽然它看起来只处理很小的 corner case,但这些场景在规则链里非常常见:

  • 常量折叠后产生空关系;
  • 子查询展开后变成 Values
  • IN 列表去重;
  • grand total on empty input。

如果不提前规约,后续规则和执行器都得带着这些"本可常量化"的节点继续走。

7. 代表性测试

RelOptRulesTest 中这条规则的直接测试非常集中:

  • testAggregateValuesRuleWithInRepeatingValues
  • testAggregateValuesRuleWithRepeatingValues
  • testAggregateValuesRuleWithAggregation
  • testAggregateValuesRuleWithSameRowType
  • testAggregateValuesRuleWithDifferentRowTypes
  • testEmptyAggregateEmptyKeyWithAggregateValuesRule

这些测试分别覆盖:

  • Values 去重;
  • 空输入上的聚合结果;
  • row type 相同/不同的区别;
  • grand total on empty input。

总结

AggregateValuesRule 是一条典型的"小输入折叠规则":

  1. Values + 全局聚合时,直接产出一行常量结果;
  2. 纯去重 Aggregate 时,直接把 Values 自身去重;
  3. 只在语义非常明确的场景下生效。

它的价值不在复杂度,而在于把一类完全可以在优化阶段完成的计算提前消掉。

相关推荐
BullSmall11 小时前
Another Redis Desktop Manager(ARDM)下载指南
数据库·redis·缓存
SelectDB11 小时前
Apache Doris 倒排索引工作原理:全文检索提速 59 倍,点查提速 14 倍
数据库
码农颜11 小时前
5.1.1 原⼦性
数据库·mysql
lupai11 小时前
手机归属地查询 API 新手接入指南
大数据·智能手机·api接口
机建狂魔11 小时前
Codex 接入第三方模型 API 实战:以 Mimo 为例
java·服务器·数据库·ai·ai编程·codex
数据皮皮侠AI11 小时前
上市公司数字供应链金融指数(2010-2024)
大数据·人工智能·算法
山峰哥11 小时前
数据库工程与SQL调优:从慢查询到秒级响应的实战之路
java·开发语言·数据库·sql·深度优先·启发式算法
moMo12 小时前
# 向量数据库入门:从"关键词匹配"到"语义理解"
数据库
ACP广源盛1392462567312 小时前
DeepSeek‑V4‑Flash 公测@ACP#昇腾 950 国产算力组合落地,国产 PCIe 交换芯片 IX9104 有哪些硬件机会
大数据·数据库·人工智能·分布式·单片机·嵌入式硬件·microsoft
进击的女IT12 小时前
通过mysql中的Data目录恢复数据库数据
数据库·mysql