【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. 只在语义非常明确的场景下生效。

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

相关推荐
2301_803875615 小时前
C#怎么使用TopLevel顶级语句 C#顶级语句怎么写如何省略Main方法简化控制台程序【语法】
jvm·数据库·python
九皇叔叔5 小时前
MySQL 8.0 测试库安装
数据库·mysql
baidu_340998825 小时前
SQL多维度数据聚合技巧_利用GROUP BY WITH ROLLUP实现
jvm·数据库·python
m0_743623925 小时前
Python如何计算NumPy数组的协方差矩阵_调用cov函数进行特征分析
jvm·数据库·python
qq_380619165 小时前
Layui表格怎么隐藏指定列
jvm·数据库·python
21439656 小时前
mysql如何通过yum源快速安装_mysql官方yum安装教程
jvm·数据库·python
qq_654366986 小时前
mysql如何选择存储引擎_mysql MyISAM与InnoDB深度对比
jvm·数据库·python
21439656 小时前
MySQL升级如何回滚到旧版本_灾难恢复方案与快照备份恢复
jvm·数据库·python
qq_372154236 小时前
HTML怎么处理右键菜单_HTML contextmenu自定义(已废弃)替代方案【指南】
jvm·数据库·python
treacle田6 小时前
达梦数据库-数据库审计02-记录总结
数据库·达梦数据库·数据库对象级审计