diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java index 60f4a074f3bf..9eeb972ea612 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java @@ -32,6 +32,7 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.util.Litmus; +import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; import org.apache.calcite.util.trace.CalciteTrace; @@ -39,6 +40,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -319,15 +321,12 @@ RelNode buildCheapestPlan(VolcanoPlanner planner) { */ void propagateCostImprovements(VolcanoPlanner planner, RelMetadataQuery mq, RelNode rel, Set activeSet) { - for (RelSubset subset : set.subsets) { - if (rel.getTraitSet().satisfies(subset.traitSet)) { - subset.propagateCostImprovements0(planner, mq, rel, activeSet); - } - } + hierarchicalPropagateImprovement(planner, mq, this, rel, activeSet); } void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, - RelNode rel, Set activeSet) { + RelNode rel, Set activeSet, + ArrayDeque> propagateQueue) { ++timestamp; if (!activeSet.add(this)) { @@ -340,7 +339,8 @@ void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, try { final RelOptCost cost = planner.getCost(rel, mq); if (cost.isLt(bestCost)) { - LOGGER.trace("Subset cost improved: subset [{}] cost was {} now {}", this, bestCost, cost); + LOGGER.trace("Subset cost improved: subset [{}] cost was {} now {}", + this, bestCost, cost); bestCost = cost; best = rel; @@ -350,8 +350,7 @@ void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, planner.ruleQueue.recompute(this); for (RelNode parent : getParents()) { final RelSubset parentSubset = planner.getSubset(parent); - parentSubset.propagateCostImprovements(planner, mq, parent, - activeSet); + parentSubset.push(parent, propagateQueue); } planner.checkForSatisfiedConverters(set, rel); } @@ -360,6 +359,28 @@ void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, } } + void hierarchicalPropagateImprovement(VolcanoPlanner planner, RelMetadataQuery mq, + RelSubset subset, RelNode rel, Set activeSet) { + ArrayDeque> propagateQueue = new ArrayDeque<>(); + subset.push(rel, propagateQueue); + + while (!propagateQueue.isEmpty()) { + Pair first = propagateQueue.remove(); + + first.getValue() + .propagateCostImprovements0(planner, mq, first.getKey(), activeSet, + propagateQueue); + } + } + + void push(RelNode rel, ArrayDeque> propagateQueue) { + for (RelSubset subset : set.subsets) { + if (rel.getTraitSet().satisfies(subset.traitSet)) { + propagateQueue.add(Pair.of(rel, subset)); + } + } + } + public void propagateBoostRemoval(VolcanoPlanner planner) { planner.ruleQueue.recompute(this);