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 f95f74a  [CALCITE-2166] Cumulative cost of RelSubset.best RelNode is 
increased after calling RelSubset.propagateCostImprovements() for input 
RelNodes (Xiening Dai)
f95f74a is described below

commit f95f74a13a20413bb0074f0a3c94901a7a88305c
Author: Xiening Dai <[email protected]>
AuthorDate: Wed Sep 4 10:44:27 2019 -0700

    [CALCITE-2166] Cumulative cost of RelSubset.best RelNode is increased after 
calling RelSubset.propagateCostImprovements() for input RelNodes (Xiening Dai)
    
    It's possible that Subset's best cost increases when input subset's best is
    changed. In those cases, although input subset's cost is reduced, the row 
count
    can increase which causes the increase of non-cumulative cost of parent 
rel. As
    a result, the cost of parent rel can increase. If the parent rel happens to 
be
    the best rel of a given subset, we currently do nothing. And this would 
lead to
    the inconsistency of the rel node cost.
    
    Fixing this by updating the best rel node cost if it's increased. Although 
this
    approach won't garantee an optimal plan, at least it makes sure the memo is
    consistent.
    
    More details, please refer to JIRA -
    https://issues.apache.org/jira/browse/CALCITE-2166
    
    Close #1440
---
 .../org/apache/calcite/plan/volcano/RelSubset.java | 26 +++++++++++++++++-----
 .../calcite/plan/volcano/VolcanoPlanner.java       | 19 ++++++++++++----
 .../apache/calcite/test/ScannableTableTest.java    |  4 ++--
 3 files changed, 38 insertions(+), 11 deletions(-)

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 6accad3..7c78f71 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
@@ -344,15 +344,31 @@ public class RelSubset extends AbstractRelNode {
       return;
     }
     try {
-      final RelOptCost cost = planner.getCost(rel, mq);
-      if (cost.isLt(bestCost)) {
-        LOGGER.trace("Subset cost improved: subset [{}] cost was {} now {}", 
this, bestCost, cost);
+      RelOptCost cost = planner.getCost(rel, mq);
+      boolean updateBest = cost.isLt(bestCost);
+
+      // Best rel's cost is increased, we need to search for new best rel
+      if (rel == best && bestCost.isLt(cost)) {
+        updateBest = true;
+        for (RelNode node : getRels()) {
+          RelOptCost relCost = planner.getCost(node, mq);
+          if (relCost.isLt(cost)) {
+            cost = relCost;
+            rel = node;
+          }
+        }
+      }
+
+      // Update subset best cost when we find a cheaper rel or the current
+      // best's cost is changed
+      if (updateBest) {
+        LOGGER.trace("Subset cost changed: subset [{}] cost was {} now {}",
+            this, bestCost, cost);
 
         bestCost = cost;
         best = rel;
 
-        // Lower cost means lower importance. Other nodes will change
-        // too, but we'll get to them later.
+        // Recompute subset's importance and propagate cost change to parents
         planner.ruleQueue.recompute(this);
         for (RelNode parent : getParents()) {
           final RelSubset parentSubset = planner.getSubset(parent);
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 43f79c4..36f6385 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
@@ -883,10 +883,21 @@ public class VolcanoPlanner extends AbstractRelOptPlanner 
{
               subset.getDescription(), set);
         }
 
-        // Make sure best RelNode is valid
-        if (subset.best != null && !subset.set.rels.contains(subset.best)) {
-          return litmus.fail("RelSubset [{}] does not contain its best RelNode 
[{}]",
-                  subset.getDescription(), subset.best.getDescription());
+        if (subset.best != null) {
+
+          // Make sure best RelNode is valid
+          if (!subset.set.rels.contains(subset.best)) {
+            return litmus.fail("RelSubset [{}] does not contain its best 
RelNode [{}]",
+                    subset.getDescription(), subset.best.getDescription());
+          }
+
+          // Make sure bestCost is up-to-date
+          RelOptCost bestCost = getCost(subset.best, 
subset.best.getCluster().getMetadataQuery());
+          if (!subset.bestCost.equals(bestCost)) {
+            return litmus.fail("RelSubset [" + subset.getDescription()
+                            + "] has wrong best cost "
+                            + subset.bestCost + ". Correct cost is " + 
bestCost);
+          }
         }
 
         for (RelNode rel : subset.getRels()) {
diff --git a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java 
b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
index a6ea539..d627954 100644
--- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
+++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java
@@ -268,11 +268,11 @@ public class ScannableTableTest {
         + "group by \"k\"";
     final Table table = new BeatlesProjectableFilterableTable(buf, false);
     final String explain = "PLAN="
-        + "EnumerableAggregate(group=[{0}], C=[COUNT()])\n"
+        + "EnumerableAggregate(group=[{1}], C=[COUNT()])\n"
         + "  EnumerableAggregate(group=[{0, 1}])\n"
         + "    EnumerableInterpreter\n"
         + "      BindableTableScan(table=[[s, beatles]], "
-        + "filters=[[=($2, 1940)]], projects=[[2, 0]])";
+        + "filters=[[=($2, 1940)]], projects=[[0, 2]])";
     CalciteAssert.that()
         .with(newSchema("s", "beatles", table))
         .query(sql)

Reply via email to