This is an automated email from the ASF dual-hosted git repository.
hyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new 0f7dcfb [CALCITE-3819] Prune parent RelNode when merging child RelSet
with parent RelSet
0f7dcfb is described below
commit 0f7dcfbffdf2e2405c835d22af78dac7124a728f
Author: Haisheng Yuan <[email protected]>
AuthorDate: Tue Feb 25 14:05:37 2020 -0800
[CALCITE-3819] Prune parent RelNode when merging child RelSet with parent
RelSet
Suppose we have 2 RelSets:
RelSet A: rel1
RelSet B: rel2
rel1 is the parent of rel2.
If there is a transformation rule that transform rel1 to rel2, we will merge
RelSet A and B. During merge process, we can safely prune rel1 to avoid
further
rule apply on rel1 and reduce search space, more importantly, avoid cyclic
reference.
---
.../org/apache/calcite/plan/volcano/RelSet.java | 44 +++++++++++++++++++++-
.../calcite/plan/volcano/VolcanoPlanner.java | 20 ++++++----
.../calcite/plan/volcano/VolcanoRuleCall.java | 16 ++++++++
3 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index 974e331..1651219 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -23,6 +23,7 @@ import org.apache.calcite.plan.RelTrait;
import org.apache.calcite.plan.RelTraitDef;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.convert.Converter;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.util.trace.CalciteTrace;
@@ -108,6 +109,25 @@ class RelSet {
}
/**
+ * Returns the child Relset for current set
+ */
+ public Set<RelSet> getChildSets(VolcanoPlanner planner) {
+ Set<RelSet> childSets = new HashSet<>();
+ for (RelNode node : this.rels) {
+ if (node instanceof Converter) {
+ continue;
+ }
+ for (RelNode child : node.getInputs()) {
+ RelSet childSet = planner.equivRoot(((RelSubset) child).getSet());
+ if (childSet.id != this.id) {
+ childSets.add(childSet);
+ }
+ }
+ }
+ return childSets;
+ }
+
+ /**
* @return all of the {@link RelNode}s contained by any subset of this set
* (does not include the subset objects themselves)
*/
@@ -326,7 +346,29 @@ class RelSet {
if (otherSubset.bestCost.isLt(subset.bestCost)) {
changedSubsets.put(subset, otherSubset.best);
}
- for (RelNode otherRel : otherSubset.getRels()) {
+ }
+
+ Set<RelNode> parentRels = new HashSet<>(parents);
+ for (RelNode otherRel : otherSet.rels) {
+ Double importance = planner.getImportance(otherRel);
+ if (importance != null && importance == 0d) {
+ continue;
+ }
+
+ boolean pruned = false;
+ if (parentRels.contains(otherRel)) {
+ // if otherRel is a enforcing operator e.g.
+ // Sort, Exchange, do not prune it.
+ if (otherRel.getInputs().size() != 1
+ || otherRel.getInput(0).getTraitSet()
+ .satisfies(otherRel.getTraitSet())) {
+ pruned = true;
+ }
+ }
+
+ if (pruned) {
+ planner.setImportance(otherRel, 0d);
+ } else {
planner.reregister(this, otherRel);
}
}
diff --git
a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index d3bb2ec..7b2a6ac 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -856,7 +856,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
if (equivRel != null) {
final RelSubset equivSubset = getSubset(equivRel);
if (subset.set != equivSubset.set) {
- merge(equivSubset.set, subset.set);
+ merge(subset.set, equivSubset.set, !(rel instanceof RelSubset));
}
}
result = subset;
@@ -1073,6 +1073,11 @@ public class VolcanoPlanner extends
AbstractRelOptPlanner {
}
}
+ Double getImportance(RelNode rel) {
+ assert rel != null;
+ return relImportances.get(rel);
+ }
+
/**
* Dumps the internal state of this VolcanoPlanner to a writer.
*
@@ -1398,7 +1403,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
assert equivSubset.getTraitSet().equals(
subset.getTraitSet());
assert equivSubset.set != subset.set;
- merge(equivSubset.set, subset.set);
+ merge(equivSubset.set, subset.set, true);
}
}
}
@@ -1499,7 +1504,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
return changeCount > 0;
}
- private RelSet merge(RelSet set, RelSet set2) {
+ private RelSet merge(RelSet set, RelSet set2, boolean enableSwap) {
assert set != set2 : "pre: set != set2";
// Find the root of set2's equivalence tree.
@@ -1514,7 +1519,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
// If necessary, swap the sets, so we're always merging the newer set
// into the older.
- if (set.id > set2.id) {
+ if (enableSwap && set.id > set2.id) {
RelSet t = set;
set = set2;
set2 = t;
@@ -1536,7 +1541,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
return set;
}
- private static RelSet equivRoot(RelSet s) {
+ static RelSet equivRoot(RelSet s) {
RelSet p = s; // iterates at twice the rate, to detect cycles
while (s.equivalentSet != null) {
p = forward2(s, p);
@@ -1652,7 +1657,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
LOGGER.trace(
"Register #{} {} (and merge sets, because it is a conversion)",
rel.getId(), rel.getDigest());
- merge(set, childSet);
+ merge(set, childSet, true);
registerCount++;
// During the mergers, the child set may have changed, and since
@@ -1774,7 +1779,8 @@ public class VolcanoPlanner extends AbstractRelOptPlanner
{
&& (set != null)
&& (set.equivalentSet == null)) {
LOGGER.trace("Register #{} {}, and merge sets", subset.getId(), subset);
- merge(set, subset.set);
+ boolean enableSwap = !set.getChildSets(this).contains(subset.set);
+ merge(subset.set, set, enableSwap);
registerCount++;
}
return subset;
diff --git
a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
index af5d1ed..6256d3e 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java
@@ -123,6 +123,22 @@ public class VolcanoRuleCall extends RelOptRuleCall {
volcanoPlanner.listener.ruleProductionSucceeded(event);
}
+ for (int i = 0; i < rels.length; i++) {
+ if (rel == rels[i]) {
+ if (i == 0) {
+ return;
+ }
+ volcanoPlanner.setImportance(rels[0], 0d);
+ break;
+ }
+
+ final RelNode relCopy = rel;
+ if (rels[i].getInputs().stream().anyMatch(n -> n == relCopy)) {
+ volcanoPlanner.setImportance(rels[0], 0d);
+ break;
+ }
+ }
+
// Registering the root relational expression implicitly registers
// its descendants. Register any explicit equivalences first, so we
// don't register twice and cause churn.