OptD项目中MergeGroup的设计问题与解决方案
背景介绍
在数据库查询优化器OptD项目中,MergeGroup是一个特殊的设计元素,它的引入源于两个主要需求:测试OptD级联核心功能和缩小搜索空间。然而,这个设计在实际应用中却带来了一系列复杂问题。
MergeGroup的起源
最初,开发团队尝试在级联规则中添加启发式规则。例如,当过滤谓词恒为真时,eliminateFilter规则会移除过滤节点。这导致了必须引入MergeGroup来处理逻辑等价的分组情况。
具体来说,当遇到类似Filter(true)
这样的表达式时,优化器会识别到过滤操作实际上不改变数据,因此将过滤节点所在分组与其子分组合并。这种合并操作在传统级联优化器论文或Columbia论文中都没有明确定义,属于OptD项目的实验性设计。
MergeGroup带来的问题
操作树中的循环引用
MergeGroup最直接的问题是可能导致操作树中出现循环引用。以一个简单查询Select * from t1 where true
为例:
初始分组结构:
- G1: filter(true) -> child(G2)
- G2: Scan(t1)
应用eliminateFilter规则后变为:
- G1: filter(true)->child(G2), Scan(t1)
- G2: 合并到G1
这种结构在执行查询时没有问题,但当需要遍历操作树时,就会出现循环引用问题,因为表达式会指向自身作为子节点。这对连接顺序枚举、树遍历、调试打印等功能都造成了严重影响。
任务触发顺序问题
OptD中任务的触发顺序是精心设计的,遵循Columbia论文的原则。MergeGroup的引入可能导致任务触发顺序错乱:
- 优化过程通常从根组开始,自上而下探索所有表达式
- 如果两个组在合并前已被不同方式探索过
- 合并后可能导致某些表达式被遗漏
这种情况非常隐蔽,难以发现和调试。
技术深入分析
传统优化器的做法
在实际的优化器实现中,通常在级联框架之前会有重写阶段或准备阶段来规范化表达式。这意味着在级联框架内部实际上不需要实现这类启发式规则。MergeGroup的引入某种程度上违背了这一设计原则。
任务调度机制的脆弱性
OptD的任务调度机制包括:
- OptimizeGroup:根组优化任务
- OptimizeExpr:处理组内所有逻辑表达式
- OptimizeInput:处理物理表达式并计算成本
- ExploreGroup:探索子组
MergeGroup破坏了这种精心设计的任务流,可能导致:
- 某些组被提前探索而无法再次探索
- 合并源组的新表达式被遗漏
- 优化过程不完整
解决方案与未来方向
基于上述问题,项目团队认识到MergeGroup会导致调试困难和各种棘手问题,决定移除这一设计。具体考虑包括:
- 移除MergeGroup机制
- 将启发式规则移出级联逻辑
- 采用更标准的表达式规范化方法
在后续开发中,项目通过重写memo表结构彻底解决了这一问题,使优化器更加健壮和可靠。这一改进体现了数据库查询优化器设计中平衡创新与标准实践的重要性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考