当前位置: 首页 > news >正文

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

AggregateRemoveRule用来删掉“其实已经没有必要存在”的Aggregate。它成立的前提是:输入在当前 group key 上已经唯一,而且所有聚合调用都可以被化成单行表达式或常量。本文结合源码实现,分析这条规则为什么能把SUM(x)退化成x,为什么对SUM0特别保守,以及它是如何在删除聚合后补出对应Project的。

1. 规则要解决什么问题

如果输入已经在 group key 上唯一,例如:

SELECTempno,SUM(sal)FROMempGROUPBYempno,deptno;

empno本身就是唯一键,那么每个组实际上只有一行。此时:

SUM(sal)

和直接取该行的sal是等价的,整个Aggregate就可能被移除。

2. 触发条件

规则先用areColumnsUnique(input, aggregate.getGroupSet())判断输入在 group key 上是否唯一。

如果不唯一,直接退出。

然后还要求每个AggregateCall都满足canFlatten(...),也就是:

  • 没有FILTER
  • 聚合函数是SqlSingletonAggFunctionSqlStaticAggFunction

3. singleton 聚合和 static 聚合的区别

3.1 singleton

SUM(x)MIN(x)MAX(x)这类,在“每组最多一行”时可以退化成单行表达式。

源码会通过:

splitter.singleton(...)

得到对应表达式。

3.2 static

某些聚合在特定 group set 下甚至可以直接化成常量,例如GROUPING(...)一类静态结果。

源码通过:

staticAggFunction.constant(...)

直接生成常量表达式。

4. 为什么遇到 SUM0 要直接退出

源码里专门有:

if(aggregation.getKind()==SqlKind.SUM0){return;}

注释说明是为了避免潜在的无限规则匹配。因为SUM0常常来自其他规则把SUM规约后的中间形态,如果这里继续激进消掉,可能和其他规则来回震荡。

5. 删除 Aggregate 后怎么保持输出不变

规则删掉Aggregate后并不会直接返回原输入,而是:

  1. 先把新输入压入RelBuilder
  2. 构造投影列表:
    • group key 列保留;
    • 每个聚合调用变成对应表达式或常量;
  3. 如果原 aggregate 只有 group key 没有聚合函数,而输入列更多,还要补一层Project保持列裁剪效果。

6. 为什么这条规则依赖元数据

它成立的关键不在语法,而在:

mq.areColumnsUnique(...)

如果元数据不能证明输入唯一,哪怕用户肉眼觉得“这看起来就只有一行”,规则也不会触发。

这说明它是一条高度依赖唯一性推断的替换规则。

7. 代表性测试

RelOptRulesTest里 8010 行附近有一整组测试:

  • testAggregateRemove1testAggregateRemove7

覆盖了:

  • 输入唯一时应删除;
  • 无聚合函数时应删除;
  • COUNT(mgr)因可空列需要正确转表达式;
  • AVG这类不能删;
  • 非 simple aggregate 不能删;
  • group key 不唯一不能删。

总结

AggregateRemoveRule的核心逻辑很明确:

  1. 输入已经在 group key 上唯一;
  2. 聚合函数可以退化成单行表达式或静态常量;
  3. 删除Aggregate后再用Project保持输出 schema。

它是一条典型的“元数据驱动消除规则”,真正难的不是删节点,而是先证明“删掉以后语义完全不变”。

http://www.cnnetsun.cn/news/1821065.html

相关文章:

  • FireRedASR-AED-L实现Python语音识别:从音频到文本的完整教程
  • 如何用Mermaid Live Editor快速创建专业图表:免费实时编辑完全指南
  • 网盘直链下载助手终极指南:八大网盘文件下载神器,轻松获取真实下载链接
  • 3步掌握DriverStore Explorer:彻底解决Windows驱动臃肿的终极指南
  • 告别ATE测试瓶颈:手把手教你用Tessent BFD优化SSN内部总线速率与Loop Timing
  • 从零到精通:GraphvizOnline在线流程图工具完全指南
  • 3大核心功能解析:ArchivePasswordTestTool高效恢复加密压缩包密码
  • 告别兼容性困扰:Python与VBA双引擎实现xls到xlsx的自动化批量升级
  • DNS服务部署实施手册
  • 别再只写网页了!用Electron + Node.js + Chromium把你的Vue/React项目打包成桌面软件(附完整配置)
  • 3分钟掌握GoB插件:打造Blender与ZBrush无缝协作的3D建模工作流
  • 深入拆解 ReentrantLock:从底层实现到生产最佳实践
  • 3大核心技术解析:Betaflight Configurator如何重塑无人机调参体验
  • Topit:让Mac多窗口工作变得轻松高效的终极窗口置顶工具
  • RuoYi系统角色权限划分与控制
  • 从手机充电到实验室电源:拆解恒流源电路在5个真实产品中的应用
  • 海景美女图FLUX.1参数详解:引导强度3.5为何最优?随机种子-1的生成逻辑揭秘
  • samba服务器的安装
  • GitHub汉化插件终极指南:5分钟打造全中文开发环境
  • 终极指南:如何在Windows 10/11上快速安装开源Android子系统WSABuilds
  • GTE-Base-ZH与卷积神经网络结合:多模态内容理解初探
  • AIGlasses_for_navigation开发环境配置:Node.js安装及后端服务框架搭建
  • 2026年揭秘!日照那些让你放心吃海鲜,绝不宰客的宝藏店铺
  • OpenClaw 新手部署教程:WSL2 静默自启 + Windows 浏览器访问
  • 3D游戏开发实战:Unity中快速计算点到直线距离的两种高效方法
  • 昨天还在说没对象,今天工作都没了。 那我有什么?有房贷啊,还有一身过劳的臭毛病
  • ClawdBot惊艳效果:模糊车牌图片→OCR识别→中英双语翻译+校验
  • AI论文写作哪个好?2026年精选6款AI写论文软件排行榜,AI率精准控制无压力!
  • Defender Control:彻底掌控Windows安全防护的3种实用方法
  • CUDA driver error: invalid argument问题修改