Apache Calcite VolcanoPlanner代价计算解析与源码调试方法
calcite的volcanoPlanner优化器是基于代价的,并且使用动态规划算法计算最优的关系表达式树。在通过规则变换后出现一个新的RelNode表达树结构时,对它与其子表达式进行注册的过程中会计算这个新的RelNode树结构的RelOptCost即使用这个表达式的代价。
要弄清楚Calcite的VolcanoPlanner优化过程,了解它是如何计算RelNode的cost是比较重要的一环。这一篇文章分析Calcite计算RelNode的cost关键代码,由于Calicite在计算cost的时候会动态生成代码与编译,直接看源码不好理解整个过程,需要debug跟随着代码运行来分析,这里也会讲解如何对calcite进行debug。
以下分析源码基于Apache Calcite 1.23.0版本
代价计算方法
VolcanoPlanner的getCost方法
VolcanoPlanner在需要获取一个RelNode的cost数据的时候都会调用getCost
方法进行计算。
public RelOptCost getCost(RelNode rel, RelMetadataQuery mq) {
assert rel != null : "pre-condition: rel != null";
if (rel instanceof RelSubset) {
return ((RelSubset) rel).bestCost;
}
if (noneConventionHasInfiniteCost
&& rel.getTraitSet().getTrait(ConventionTraitDef.INSTANCE) == Convention.NONE) {
return costFactory.makeInfiniteCost();
}
RelOptCost cost = mq.getNonCumulativeCost(rel);
if (!zeroCost.isLt(cost)) {
// cost must be positive, so nudge it
cost = costFactory.makeTinyCost();
}
for (RelNode input : rel.getInputs()) {
cost = cost.plus(getCost(input, mq))