>From Vijay Sarathy <[email protected]>:

Vijay Sarathy has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17550 )


Change subject: [ASTERIXDB-3195][COMP] Need a debug option to enumerate all 
plans without pruning during join enumeration.
......................................................................

[ASTERIXDB-3195][COMP] Need a debug option to enumerate all plans without 
pruning during join enumeration.

Change-Id: Ie99c7310ebfca075f3211f32195fb2ad5df7c470
---
M 
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/OptimizationConfUtil.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
M 
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
M 
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/PhysicalOptimizationConfig.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
M 
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
8 files changed, 223 insertions(+), 137 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/50/17550/1

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
index f4ec7c4..13ae156 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
@@ -85,13 +85,13 @@
                 CompilerProperties.COMPILER_SUBPLAN_NESTEDPUSHDOWN_KEY, 
CompilerProperties.COMPILER_ARRAYINDEX_KEY,
                 CompilerProperties.COMPILER_CBO_KEY, 
CompilerProperties.COMPILER_CBO_TEST_KEY,
                 CompilerProperties.COMPILER_FORCE_JOIN_ORDER_KEY, 
CompilerProperties.COMPILER_QUERY_PLAN_SHAPE_KEY,
-                CompilerProperties.COMPILER_MIN_MEMORY_ALLOCATION_KEY, 
CompilerProperties.COMPILER_COLUMN_FILTER_KEY,
-                CompilerProperties.COMPILER_BATCH_LOOKUP_KEY, 
FunctionUtil.IMPORT_PRIVATE_FUNCTIONS,
-                FuzzyUtils.SIM_FUNCTION_PROP_NAME, 
FuzzyUtils.SIM_THRESHOLD_PROP_NAME,
-                StartFeedStatement.WAIT_FOR_COMPLETION, 
FeedActivityDetails.FEED_POLICY_NAME,
-                FeedActivityDetails.COLLECT_LOCATIONS, 
SqlppQueryRewriter.INLINE_WITH_OPTION,
-                SqlppExpressionToPlanTranslator.REWRITE_IN_AS_OR_OPTION, 
"hash_merge", "output-record-type",
-                DisjunctivePredicateToJoinRule.REWRITE_OR_AS_JOIN_OPTION,
+                CompilerProperties.COMPILER_CBO_PRUNING_KEY, 
CompilerProperties.COMPILER_MIN_MEMORY_ALLOCATION_KEY,
+                CompilerProperties.COMPILER_COLUMN_FILTER_KEY, 
CompilerProperties.COMPILER_BATCH_LOOKUP_KEY,
+                FunctionUtil.IMPORT_PRIVATE_FUNCTIONS, 
FuzzyUtils.SIM_FUNCTION_PROP_NAME,
+                FuzzyUtils.SIM_THRESHOLD_PROP_NAME, 
StartFeedStatement.WAIT_FOR_COMPLETION,
+                FeedActivityDetails.FEED_POLICY_NAME, 
FeedActivityDetails.COLLECT_LOCATIONS,
+                SqlppQueryRewriter.INLINE_WITH_OPTION, 
SqlppExpressionToPlanTranslator.REWRITE_IN_AS_OR_OPTION,
+                "hash_merge", "output-record-type", 
DisjunctivePredicateToJoinRule.REWRITE_OR_AS_JOIN_OPTION,
                 SetAsterixPhysicalOperatorsRule.REWRITE_ATTEMPT_BATCH_ASSIGN,
                 EquivalenceClassUtils.REWRITE_INTERNAL_QUERYUID_PK, 
SqlppQueryRewriter.SQL_COMPAT_OPTION));
     }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
index f2319c4..3a7736e 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
@@ -88,6 +88,8 @@
             throws AlgebricksException {
         boolean cboMode = this.getCBOMode(context);
         boolean cboTestMode = this.getCBOTestMode(context);
+        boolean cboPruningMode = this.getCBOPruningMode(context);
+
         if (!(cboMode || cboTestMode)) {
             return false;
         }
@@ -131,7 +133,7 @@

         int numberOfFromTerms = emptyTupleAndDataSourceOps.size();

-        joinEnum.initEnum((AbstractLogicalOperator) op, cboMode, cboTestMode, 
numberOfFromTerms,
+        joinEnum.initEnum((AbstractLogicalOperator) op, cboMode, cboTestMode, 
cboPruningMode, numberOfFromTerms,
                 emptyTupleAndDataSourceOps, joinLeafInputsHashMap, joinOps, 
assignOps, context);

         if (cboMode) {
@@ -225,6 +227,11 @@
         return physOptConfig.getCBOTestMode();
     }

+    private boolean getCBOPruningMode(IOptimizationContext context) {
+        PhysicalOptimizationConfig physOptConfig = 
context.getPhysicalOptimizationConfig();
+        return physOptConfig.getCBOPruningMode();
+    }
+
     /**
      * Should not see any kind of joins here. store the emptyTupeSourceOp and 
DataSource operators.
      * Each leaf input will normally have both, but sometimes only 
emptyTupeSourceOp will be present (in lists)
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
index 46a67e8..c033656 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinEnum.java
@@ -104,6 +104,7 @@
     protected Stats stats;
     private boolean cboMode;
     private boolean cboTestMode;
+    protected boolean cboPruningMode;
     protected int numberOfTerms;
     private AbstractLogicalOperator op;
     protected boolean connectedJoinGraph;
@@ -115,7 +116,8 @@
     public JoinEnum() {
     }

-    protected void initEnum(AbstractLogicalOperator op, boolean cboMode, 
boolean cboTestMode, int numberOfFromTerms,
+    protected void initEnum(AbstractLogicalOperator op, boolean cboMode, 
boolean cboTestMode, boolean cboPruningMode,
+            int numberOfFromTerms,
             List<Pair<EmptyTupleSourceOperator, DataSourceScanOperator>> 
emptyTupleAndDataSourceOps,
             Map<EmptyTupleSourceOperator, ILogicalOperator> 
joinLeafInputsHashMap, List<ILogicalOperator> joinOps,
             List<AssignOperator> assignOps, IOptimizationContext context) {
@@ -126,6 +128,7 @@
         this.numberOfTerms = numberOfFromTerms;
         this.cboMode = cboMode;
         this.cboTestMode = cboTestMode;
+        this.cboPruningMode = cboPruningMode;
         this.connectedJoinGraph = true;
         this.optCtx = context;
         this.emptyTupleAndDataSourceOps = emptyTupleAndDataSourceOps;
@@ -607,11 +610,11 @@
                 JoinNode jnIJ = jnArray[addPlansToThisJn];
                 jnIJ.jnArrayIndex = addPlansToThisJn;
                 jnIJ.addMultiDatasetPlans(jnI, jnJ);
-                if (forceJoinOrderMode) {
+                if (forceJoinOrderMode && cboPruningMode) {
                     break;
                 }
             }
-            if (forceJoinOrderMode) {
+            if (forceJoinOrderMode && cboPruningMode) {
                 break;
             }
         }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
index fa2a144..cd2a776 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/JoinNode.java
@@ -383,7 +383,8 @@

         opCost = joinEnum.getCostMethodsHandle().costFullScan(this);
         totalCost = opCost;
-        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
opCost.costLT(this.cheapestPlanCost)) {
+        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
opCost.costLT(this.cheapestPlanCost)
+                || !joinEnum.cboPruningMode) {
             // for now just add one plan
             PlanNode pn = new PlanNode(allPlans.size(), joinEnum);
             pn.setJoinNode(this);
@@ -399,9 +400,10 @@

             allPlans.add(pn);
             this.planIndexesArray.add(pn.allPlansIndex);
-            this.cheapestPlanCost = totalCost;
-            this.cheapestPlanIndex = pn.allPlansIndex;
-            return this.cheapestPlanIndex;
+            PlanNode cheapestPlan = findCheapestPlan();
+            this.cheapestPlanCost = cheapestPlan.totalCost;
+            this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
+            return pn.allPlansIndex;
         }
         return PlanNode.NO_PLAN;
     }
@@ -548,7 +550,7 @@
             for (int i = 1; i < optionalIndexesInfo.size(); i++) {
                 newIdxCost = newIdxCost.costAdd(indexCosts.get(i)); // I0 + 
I1; I0 + I1 + I2
                 currentCost = newIdxCost.costAdd(dataCosts.get(i)); // I0 + I1 
+ D01; I0 + I1 + I2 + D012
-                if (currentCost.costLT(opCost)) { // save this cost and try 
adding one more index
+                if (currentCost.costLT(opCost) || !joinEnum.cboPruningMode) { 
// save this cost and try adding one more index
                     opCost = currentCost;
                 } else {
                     // set the selectivites of the indexes not picked to be 
-1.0, so we can set
@@ -562,14 +564,14 @@
         }

         // opCost is now the total cost of the indexes chosen along with the 
associated data scan cost.
-        if (opCost.costGT(this.cheapestPlanCost)) { // cheapest plan cost is 
the data scan cost.
+        if (opCost.costGT(this.cheapestPlanCost) && joinEnum.cboPruningMode) { 
// cheapest plan cost is the data scan cost.
             for (int j = 0; j < optionalIndexesInfo.size(); j++) {
                 optionalIndexesInfo.get(j).second = -1.0; // remove all 
indexes from consideration.
             }
         }

         totalCost = opCost.costAdd(mandatoryIndexesCost); // cost of all the 
indexes chosen
-        if (opCost.costLT(this.cheapestPlanCost) || 
mandatoryIndexesInfo.size() > 0) {
+        if (opCost.costLT(this.cheapestPlanCost) || 
mandatoryIndexesInfo.size() > 0 || !joinEnum.cboPruningMode) {
             PlanNode pn = new PlanNode(allPlans.size(), joinEnum);
             pn.setJoinNode(this);
             pn.setDatasetName(getDatasetNames().get(0));
@@ -584,8 +586,9 @@

             allPlans.add(pn);
             this.planIndexesArray.add(pn.allPlansIndex);
-            this.cheapestPlanCost = totalCost; // in the presence of mandatory 
indexes, this may not be the cheapest plan! But we have no choice!
-            this.cheapestPlanIndex = pn.allPlansIndex;
+            PlanNode cheapestPlan = findCheapestPlan();
+            this.cheapestPlanCost = cheapestPlan.totalCost; // in the presence 
of mandatory indexes, this may not be the cheapest plan! But we have no choice!
+            this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
         }
     }

@@ -683,47 +686,45 @@
         }
     }

-    private int buildHashJoinPlan(JoinNode leftJn, JoinNode rightJn, 
ILogicalExpression hashJoinExpr,
-            HashJoinExpressionAnnotation hintHashJoin) {
+    private int buildHashJoinPlan(JoinNode leftJn, JoinNode rightJn, PlanNode 
leftPlan, PlanNode rightPlan,
+            ILogicalExpression hashJoinExpr, HashJoinExpressionAnnotation 
hintHashJoin) {
         List<PlanNode> allPlans = joinEnum.allPlans;
         PlanNode pn;
         ICost hjCost, leftExchangeCost, rightExchangeCost, childCosts, 
totalCost;
         this.leftJn = leftJn;
         this.rightJn = rightJn;
-        int leftPlan = leftJn.cheapestPlanIndex;
-        int rightPlan = rightJn.cheapestPlanIndex;

         if (hashJoinExpr == null || hashJoinExpr == ConstantExpression.TRUE) {
             return PlanNode.NO_PLAN;
         }

-        if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_LEFTDEEP)
-                && !leftJn.IsBaseLevelJoinNode()) {
+        if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_LEFTDEEP) && 
!leftJn.IsBaseLevelJoinNode()
+                && joinEnum.cboPruningMode) {
             return PlanNode.NO_PLAN;
         }

         if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_RIGHTDEEP)
-                && !rightJn.IsBaseLevelJoinNode()) {
+                && !rightJn.IsBaseLevelJoinNode() && joinEnum.cboPruningMode) {
             return PlanNode.NO_PLAN;
         }
-
-        if (rightJn.cardinality * rightJn.size <= leftJn.cardinality * 
leftJn.size || hintHashJoin != null
-                || joinEnum.forceJoinOrderMode
-                || 
!joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_ZIGZAG)) {
+        boolean forceEnum = hintHashJoin != null || joinEnum.forceJoinOrderMode
+                || 
!joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_ZIGZAG)
+                || !joinEnum.cboPruningMode;
+        if (rightJn.cardinality * rightJn.size <= leftJn.cardinality * 
leftJn.size || forceEnum) {
             // We want to build with the smaller side.
             hjCost = joinEnum.getCostMethodsHandle().costHashJoin(this);
             leftExchangeCost = 
joinEnum.getCostMethodsHandle().computeHJProbeExchangeCost(this);
             rightExchangeCost = 
joinEnum.getCostMethodsHandle().computeHJBuildExchangeCost(this);
-            childCosts = 
allPlans.get(leftPlan).totalCost.costAdd(allPlans.get(rightPlan).totalCost);
+            childCosts = allPlans.get(leftPlan.allPlansIndex).totalCost
+                    .costAdd(allPlans.get(rightPlan.allPlansIndex).totalCost);
             totalCost = 
hjCost.costAdd(leftExchangeCost).costAdd(rightExchangeCost).costAdd(childCosts);
-            if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost)
-                    || hintHashJoin != null) {
+            if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost) || forceEnum) {
                 pn = new PlanNode(allPlans.size(), joinEnum);
                 pn.setJoinNode(this);
                 pn.setLeftJoinIndex(leftJn.jnArrayIndex);
                 pn.setRightJoinIndex(rightJn.jnArrayIndex);
-                pn.setLeftPlanIndex(leftPlan);
-                pn.setRightPlanIndex(rightPlan);
+                pn.setLeftPlanIndex(leftPlan.allPlansIndex);
+                pn.setRightPlanIndex(rightPlan.allPlansIndex);
                 pn.joinOp = PlanNode.JoinMethod.HYBRID_HASH_JOIN; // need to 
check that all the conditions have equality predicates ONLY.
                 pn.joinHint = hintHashJoin;
                 pn.side = HashJoinExpressionAnnotation.BuildSide.RIGHT;
@@ -734,6 +735,9 @@
                 pn.rightExchangeCost = rightExchangeCost;
                 allPlans.add(pn);
                 this.planIndexesArray.add(pn.allPlansIndex);
+                PlanNode cheapestPlan = findCheapestPlan();
+                this.cheapestPlanCost = cheapestPlan.totalCost;
+                this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
                 return pn.allPlansIndex;
             }
         }
@@ -741,48 +745,47 @@
         return PlanNode.NO_PLAN;
     }

-    private int buildBroadcastHashJoinPlan(JoinNode leftJn, JoinNode rightJn, 
ILogicalExpression hashJoinExpr,
-            BroadcastExpressionAnnotation hintBroadcastHashJoin) {
+    private int buildBroadcastHashJoinPlan(JoinNode leftJn, JoinNode rightJn, 
PlanNode leftPlan, PlanNode rightPlan,
+            ILogicalExpression hashJoinExpr, BroadcastExpressionAnnotation 
hintBroadcastHashJoin) {
         List<PlanNode> allPlans = joinEnum.allPlans;
         PlanNode pn;
         ICost bcastHjCost, leftExchangeCost, rightExchangeCost, childCosts, 
totalCost;

         this.leftJn = leftJn;
         this.rightJn = rightJn;
-        int leftPlan = leftJn.cheapestPlanIndex;
-        int rightPlan = rightJn.cheapestPlanIndex;

         if (hashJoinExpr == null || hashJoinExpr == ConstantExpression.TRUE) {
             return PlanNode.NO_PLAN;
         }

-        if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_LEFTDEEP)
-                && !leftJn.IsBaseLevelJoinNode()) {
+        if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_LEFTDEEP) && 
!leftJn.IsBaseLevelJoinNode()
+                && joinEnum.cboPruningMode) {
             return PlanNode.NO_PLAN;
         }

         if 
(joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_RIGHTDEEP)
-                && !rightJn.IsBaseLevelJoinNode()) {
+                && !rightJn.IsBaseLevelJoinNode() && joinEnum.cboPruningMode) {
             return PlanNode.NO_PLAN;
         }

-        if (rightJn.cardinality * rightJn.size <= leftJn.cardinality * 
leftJn.size || hintBroadcastHashJoin != null
-                || joinEnum.forceJoinOrderMode
-                || 
!joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_ZIGZAG)) {
+        boolean forceEnum = hintBroadcastHashJoin != null || 
joinEnum.forceJoinOrderMode
+                || 
!joinEnum.queryPlanShape.equals(AlgebricksConfig.QUERY_PLAN_SHAPE_ZIGZAG)
+                || !joinEnum.cboPruningMode;
+        if (rightJn.cardinality * rightJn.size <= leftJn.cardinality * 
leftJn.size || forceEnum) {
             // We want to broadcast and build with the smaller side.
             bcastHjCost = 
joinEnum.getCostMethodsHandle().costBroadcastHashJoin(this);
             leftExchangeCost = joinEnum.getCostHandle().zeroCost();
             rightExchangeCost = 
joinEnum.getCostMethodsHandle().computeBHJBuildExchangeCost(this);
-            childCosts = 
allPlans.get(leftPlan).totalCost.costAdd(allPlans.get(rightPlan).totalCost);
+            childCosts = allPlans.get(leftPlan.allPlansIndex).totalCost
+                    .costAdd(allPlans.get(rightPlan.allPlansIndex).totalCost);
             totalCost = 
bcastHjCost.costAdd(rightExchangeCost).costAdd(childCosts);
-            if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost)
-                    || hintBroadcastHashJoin != null) {
+            if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost) || forceEnum) {
                 pn = new PlanNode(allPlans.size(), joinEnum);
                 pn.setJoinNode(this);
                 pn.setLeftJoinIndex(leftJn.jnArrayIndex);
                 pn.setRightJoinIndex(rightJn.jnArrayIndex);
-                pn.setLeftPlanIndex(leftPlan);
-                pn.setRightPlanIndex(rightPlan);
+                pn.setLeftPlanIndex(leftPlan.allPlansIndex);
+                pn.setRightPlanIndex(rightPlan.allPlansIndex);
                 pn.joinOp = PlanNode.JoinMethod.BROADCAST_HASH_JOIN; // need 
to check that all the conditions have equality predicates ONLY.
                 pn.joinHint = hintBroadcastHashJoin;
                 pn.side = HashJoinExpressionAnnotation.BuildSide.RIGHT;
@@ -791,9 +794,11 @@
                 pn.totalCost = totalCost;
                 pn.leftExchangeCost = leftExchangeCost;
                 pn.rightExchangeCost = rightExchangeCost;
-
                 allPlans.add(pn);
                 this.planIndexesArray.add(pn.allPlansIndex);
+                PlanNode cheapestPlan = findCheapestPlan();
+                this.cheapestPlanCost = cheapestPlan.totalCost;
+                this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
                 return pn.allPlansIndex;
             }
         }
@@ -801,8 +806,9 @@
         return PlanNode.NO_PLAN;
     }

-    private int buildNLJoinPlan(JoinNode leftJn, JoinNode rightJn, 
ILogicalExpression nestedLoopJoinExpr,
-            IndexedNLJoinExpressionAnnotation hintNLJoin) throws 
AlgebricksException {
+    private int buildNLJoinPlan(JoinNode leftJn, JoinNode rightJn, PlanNode 
leftPlan, PlanNode rightPlan,
+            ILogicalExpression nestedLoopJoinExpr, 
IndexedNLJoinExpressionAnnotation hintNLJoin)
+            throws AlgebricksException {
         // Build a nested loops plan, first check if it is possible
         // left right order must be preserved and right side should be a 
single data set
         List<PlanNode> allPlans = joinEnum.allPlans;
@@ -812,8 +818,6 @@

         this.leftJn = leftJn;
         this.rightJn = rightJn;
-        int leftPlan = leftJn.cheapestPlanIndex;
-        int rightPlan = rightJn.cheapestPlanIndex;
         if (rightJn.jnArrayIndex > numberOfTerms) {
             // right side consists of more than one table
             return PlanNode.NO_PLAN; // nested loop plan not possible.
@@ -826,16 +830,16 @@
         nljCost = joinEnum.getCostMethodsHandle().costIndexNLJoin(this);
         leftExchangeCost = 
joinEnum.getCostMethodsHandle().computeNLJOuterExchangeCost(this);
         rightExchangeCost = joinEnum.getCostHandle().zeroCost();
-        childCosts = allPlans.get(leftPlan).totalCost;
+        childCosts = allPlans.get(leftPlan.allPlansIndex).totalCost;
         totalCost = nljCost.costAdd(leftExchangeCost).costAdd(childCosts);
-        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost)
-                || hintNLJoin != null) {
+        boolean forceEnum = hintNLJoin != null || joinEnum.forceJoinOrderMode 
|| !joinEnum.cboPruningMode;
+        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost) || forceEnum) {
             pn = new PlanNode(allPlans.size(), joinEnum);
             pn.setJoinNode(this);
             pn.setLeftJoinIndex(leftJn.jnArrayIndex);
             pn.setRightJoinIndex(rightJn.jnArrayIndex);
-            pn.setLeftPlanIndex(leftPlan);
-            pn.setRightPlanIndex(rightPlan);
+            pn.setLeftPlanIndex(leftPlan.allPlansIndex);
+            pn.setRightPlanIndex(rightPlan.allPlansIndex);
             pn.joinOp = PlanNode.JoinMethod.INDEX_NESTED_LOOP_JOIN;
             pn.joinHint = hintNLJoin;
             pn.joinExpr = nestedLoopJoinExpr; // save it so can be used to add 
the NESTED annotation in getNewTree.
@@ -845,13 +849,16 @@
             pn.rightExchangeCost = rightExchangeCost;
             allPlans.add(pn);
             this.planIndexesArray.add(pn.allPlansIndex);
+            PlanNode cheapestPlan = findCheapestPlan();
+            this.cheapestPlanCost = cheapestPlan.totalCost;
+            this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
             return pn.allPlansIndex;
         }
         return PlanNode.NO_PLAN;
     }

-    private int buildCPJoinPlan(JoinNode leftJn, JoinNode rightJn, 
ILogicalExpression hashJoinExpr,
-            ILogicalExpression nestedLoopJoinExpr) {
+    private int buildCPJoinPlan(JoinNode leftJn, JoinNode rightJn, PlanNode 
leftPlan, PlanNode rightPlan,
+            ILogicalExpression hashJoinExpr, ILogicalExpression 
nestedLoopJoinExpr) {
         // Now build a cartesian product nested loops plan
         List<PlanNode> allPlans = joinEnum.allPlans;
         PlanNode pn;
@@ -859,8 +866,6 @@

         this.leftJn = leftJn;
         this.rightJn = rightJn;
-        int leftPlan = leftJn.cheapestPlanIndex;
-        int rightPlan = rightJn.cheapestPlanIndex;

         ILogicalExpression cpJoinExpr = null;
         List<Integer> newJoinConditions = this.getNewJoinConditionsOnly();
@@ -883,15 +888,17 @@
         cpCost = 
joinEnum.getCostMethodsHandle().costCartesianProductJoin(this);
         leftExchangeCost = joinEnum.getCostHandle().zeroCost();
         rightExchangeCost = 
joinEnum.getCostMethodsHandle().computeCPRightExchangeCost(this);
-        childCosts = 
allPlans.get(leftPlan).totalCost.costAdd(allPlans.get(rightPlan).totalCost);
+        childCosts =
+                
allPlans.get(leftPlan.allPlansIndex).totalCost.costAdd(allPlans.get(rightPlan.allPlansIndex).totalCost);
         totalCost = cpCost.costAdd(rightExchangeCost).costAdd(childCosts);
-        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost)) {
+        boolean forceEnum = joinEnum.forceJoinOrderMode || 
!joinEnum.cboPruningMode;
+        if (this.cheapestPlanIndex == PlanNode.NO_PLAN || 
totalCost.costLT(this.cheapestPlanCost) || forceEnum) {
             pn = new PlanNode(allPlans.size(), joinEnum);
             pn.setJoinNode(this);
             pn.setLeftJoinIndex(leftJn.jnArrayIndex);
             pn.setRightJoinIndex(rightJn.jnArrayIndex);
-            pn.setLeftPlanIndex(leftPlan);
-            pn.setRightPlanIndex(rightPlan);
+            pn.setLeftPlanIndex(leftPlan.allPlansIndex);
+            pn.setRightPlanIndex(rightPlan.allPlansIndex);
             pn.joinOp = PlanNode.JoinMethod.CARTESIAN_PRODUCT_JOIN;
             pn.joinExpr = Objects.requireNonNullElse(cpJoinExpr, 
ConstantExpression.TRUE);
             pn.opCost = cpCost;
@@ -900,22 +907,44 @@
             pn.rightExchangeCost = rightExchangeCost;
             allPlans.add(pn);
             this.planIndexesArray.add(pn.allPlansIndex);
+            PlanNode cheapestPlan = findCheapestPlan();
+            this.cheapestPlanCost = cheapestPlan.totalCost;
+            this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
             return pn.allPlansIndex;
         }
         return PlanNode.NO_PLAN;
     }

-    protected Pair<Integer, ICost> addMultiDatasetPlans(JoinNode leftJn, 
JoinNode rightJn) throws AlgebricksException {
+    protected void addMultiDatasetPlans(JoinNode leftJn, JoinNode rightJn) 
throws AlgebricksException {
+        PlanNode leftPlan, rightPlan;
+
+        if (joinEnum.cboPruningMode) {
+            leftPlan = leftJn.findCheapestPlan();
+            rightPlan = rightJn.findCheapestPlan();
+            addMultiDatasetPlans(leftJn, rightJn, leftPlan, rightPlan);
+        } else {
+            for (int leftPlanIndex : leftJn.planIndexesArray) {
+                leftPlan = joinEnum.allPlans.get(leftPlanIndex);
+                for (int rightPlanIndex : rightJn.planIndexesArray) {
+                    rightPlan = joinEnum.allPlans.get(rightPlanIndex);
+                    addMultiDatasetPlans(leftJn, rightJn, leftPlan, rightPlan);
+                }
+            }
+        }
+    }
+
+    protected void addMultiDatasetPlans(JoinNode leftJn, JoinNode rightJn, 
PlanNode leftPlan, PlanNode rightPlan)
+            throws AlgebricksException {
         this.leftJn = leftJn;
         this.rightJn = rightJn;
         ICost noJoinCost = joinEnum.getCostHandle().maxCost();

         if (leftJn.planIndexesArray.size() == 0 || 
rightJn.planIndexesArray.size() == 0) {
-            return new Pair<>(PlanNode.NO_PLAN, noJoinCost);
+            return;
         }

         if (this.cardinality >= Cost.MAX_CARD) {
-            return new Pair<>(PlanNode.NO_PLAN, noJoinCost); // no card hint 
available, so do not add this plan
+            return; // no card available, so do not add this plan
         }

         List<Integer> newJoinConditions = this.getNewJoinConditionsOnly(); // 
these will be a subset of applicable join conditions.
@@ -925,13 +954,13 @@
         if ((newJoinConditions.size() == 0) && joinEnum.connectedJoinGraph) {
             // at least one plan must be there at each level as the graph is 
fully connected.
             if (leftJn.cardinality * rightJn.cardinality > 10000.0) {
-                return new Pair<>(PlanNode.NO_PLAN, noJoinCost);
+                return;
             }
         }

         double current_card = this.cardinality;
         if (current_card >= Cost.MAX_CARD) {
-            return new Pair<>(PlanNode.NO_PLAN, noJoinCost); // no card hint 
available, so do not add this plan
+            return; // no card available, so do not add this plan
         }

         int hjPlan, commutativeHjPlan, bcastHjPlan, commutativeBcastHjPlan, 
nljPlan, commutativeNljPlan, cpPlan,
@@ -944,7 +973,7 @@
         IndexedNLJoinExpressionAnnotation hintNLJoin = 
joinEnum.findNLJoinHint(newJoinConditions);

         if (leftJn.cheapestPlanIndex == PlanNode.NO_PLAN || 
rightJn.cheapestPlanIndex == PlanNode.NO_PLAN) {
-            return new Pair<>(PlanNode.NO_PLAN, noJoinCost);
+            return;
         }

         if (hintHashJoin != null) {
@@ -963,12 +992,13 @@
                         || rightJn.aliases.contains(buildOrProbeObject)))
                         || (probe && 
(leftJn.datasetNames.contains(buildOrProbeObject)
                                 || 
leftJn.aliases.contains(buildOrProbeObject)))) {
-                    hjPlan = buildHashJoinPlan(leftJn, rightJn, hashJoinExpr, 
hintHashJoin);
+                    hjPlan = buildHashJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, hashJoinExpr, hintHashJoin);
                 } else if ((build && 
(leftJn.datasetNames.contains(buildOrProbeObject)
                         || leftJn.aliases.contains(buildOrProbeObject)))
                         || (probe && 
(rightJn.datasetNames.contains(buildOrProbeObject)
                                 || 
rightJn.aliases.contains(buildOrProbeObject)))) {
-                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, hintHashJoin);
+                    commutativeHjPlan =
+                            buildHashJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, hashJoinExpr, hintHashJoin);
                 }
             }
             if (hjPlan == PlanNode.NO_PLAN && commutativeHjPlan == 
PlanNode.NO_PLAN) {
@@ -984,21 +1014,24 @@
                                         (build ? "build " : "probe ") + "with 
" + buildOrProbeObject));
                     }
                 }
-                hjPlan = buildHashJoinPlan(leftJn, rightJn, hashJoinExpr, 
null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, null);
+                hjPlan = buildHashJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeBcastHjPlan = 
buildBroadcastHashJoinPlan(rightJn, leftJn, hashJoinExpr, null);
+                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeBcastHjPlan =
+                            buildBroadcastHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                nljPlan = buildNLJoinPlan(leftJn, rightJn, nestedLoopJoinExpr, 
null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeNljPlan = buildNLJoinPlan(rightJn, leftJn, 
nestedLoopJoinExpr, null);
+                nljPlan = buildNLJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, nestedLoopJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeNljPlan =
+                            buildNLJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, nestedLoopJoinExpr, null);
                 }
-                cpPlan = buildCPJoinPlan(leftJn, rightJn, hashJoinExpr, 
nestedLoopJoinExpr);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeCpPlan = buildCPJoinPlan(rightJn, leftJn, 
hashJoinExpr, nestedLoopJoinExpr);
+                cpPlan = buildCPJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
hashJoinExpr, nestedLoopJoinExpr);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeCpPlan =
+                            buildCPJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, hashJoinExpr, nestedLoopJoinExpr);
                 }
             }
         } else if (hintBroadcastHashJoin != null) {
@@ -1012,17 +1045,19 @@
             if (validBroadcastObject) {
                 joinEnum.joinHints.put(hintBroadcastHashJoin, null);
                 if (rightJn.datasetNames.contains(broadcastObject) || 
rightJn.aliases.contains(broadcastObject)) {
-                    bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, hintBroadcastHashJoin);
+                    bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr,
+                            hintBroadcastHashJoin);
                 } else if (leftJn.datasetNames.contains(broadcastObject) || 
leftJn.aliases.contains(broadcastObject)) {
-                    commutativeBcastHjPlan =
-                            buildBroadcastHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, hintBroadcastHashJoin);
+                    commutativeBcastHjPlan = 
buildBroadcastHashJoinPlan(rightJn, leftJn, rightPlan, leftPlan,
+                            hashJoinExpr, hintBroadcastHashJoin);
                 }
             } else if (broadcastObject == null) {
                 joinEnum.joinHints.put(hintBroadcastHashJoin, null);
-                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, hintBroadcastHashJoin);
+                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr,
+                        hintBroadcastHashJoin);
                 if (!joinEnum.forceJoinOrderMode) {
-                    commutativeBcastHjPlan =
-                            buildBroadcastHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, hintBroadcastHashJoin);
+                    commutativeBcastHjPlan = 
buildBroadcastHashJoinPlan(rightJn, leftJn, rightPlan, leftPlan,
+                            hashJoinExpr, hintBroadcastHashJoin);
                 }
             }
             if (bcastHjPlan == PlanNode.NO_PLAN && commutativeBcastHjPlan == 
PlanNode.NO_PLAN) {
@@ -1039,28 +1074,32 @@
                     }
                 }

-                hjPlan = buildHashJoinPlan(leftJn, rightJn, hashJoinExpr, 
null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, null);
+                hjPlan = buildHashJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeBcastHjPlan = 
buildBroadcastHashJoinPlan(rightJn, leftJn, hashJoinExpr, null);
+                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeBcastHjPlan =
+                            buildBroadcastHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                nljPlan = buildNLJoinPlan(leftJn, rightJn, nestedLoopJoinExpr, 
null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeNljPlan = buildNLJoinPlan(rightJn, leftJn, 
nestedLoopJoinExpr, null);
+                nljPlan = buildNLJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, nestedLoopJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeNljPlan =
+                            buildNLJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, nestedLoopJoinExpr, null);
                 }
-                cpPlan = buildCPJoinPlan(leftJn, rightJn, hashJoinExpr, 
nestedLoopJoinExpr);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeCpPlan = buildCPJoinPlan(rightJn, leftJn, 
hashJoinExpr, nestedLoopJoinExpr);
+                cpPlan = buildCPJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
hashJoinExpr, nestedLoopJoinExpr);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeCpPlan =
+                            buildCPJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, hashJoinExpr, nestedLoopJoinExpr);
                 }
             }
         } else if (hintNLJoin != null) {
             joinEnum.joinHints.put(hintNLJoin, null);
-            nljPlan = buildNLJoinPlan(leftJn, rightJn, nestedLoopJoinExpr, 
hintNLJoin);
+            nljPlan = buildNLJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
nestedLoopJoinExpr, hintNLJoin);
             if (!joinEnum.forceJoinOrderMode) {
-                commutativeNljPlan = buildNLJoinPlan(rightJn, leftJn, 
nestedLoopJoinExpr, hintNLJoin);
+                commutativeNljPlan =
+                        buildNLJoinPlan(rightJn, leftJn, rightPlan, leftPlan, 
nestedLoopJoinExpr, hintNLJoin);
             }
             if (nljPlan == PlanNode.NO_PLAN && commutativeNljPlan == 
PlanNode.NO_PLAN) {
                 // Hints are attached to predicates, so newJoinConditions 
should not be empty, but adding the check to be safe.
@@ -1074,35 +1113,39 @@
                                         ErrorCode.INAPPLICABLE_HINT, "index 
nested loop join", "ignored"));
                     }
                 }
-                hjPlan = buildHashJoinPlan(leftJn, rightJn, hashJoinExpr, 
null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, null);
+                hjPlan = buildHashJoinPlan(leftJn, rightJn, leftPlan, 
rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, null);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeBcastHjPlan = 
buildBroadcastHashJoinPlan(rightJn, leftJn, hashJoinExpr, null);
+                bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr, null);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeBcastHjPlan =
+                            buildBroadcastHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
                 }
-                cpPlan = buildCPJoinPlan(leftJn, rightJn, hashJoinExpr, 
nestedLoopJoinExpr);
-                if (!joinEnum.forceJoinOrderMode) {
-                    commutativeCpPlan = buildCPJoinPlan(rightJn, leftJn, 
hashJoinExpr, nestedLoopJoinExpr);
+                cpPlan = buildCPJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
hashJoinExpr, nestedLoopJoinExpr);
+                if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                    commutativeCpPlan =
+                            buildCPJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, hashJoinExpr, nestedLoopJoinExpr);
                 }
             }
         } else {
-            hjPlan = buildHashJoinPlan(leftJn, rightJn, hashJoinExpr, null);
-            if (!joinEnum.forceJoinOrderMode) {
-                commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
hashJoinExpr, null);
+            hjPlan = buildHashJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
hashJoinExpr, null);
+            if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                commutativeHjPlan = buildHashJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, hashJoinExpr, null);
             }
-            bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
hashJoinExpr, null);
-            if (!joinEnum.forceJoinOrderMode) {
-                commutativeBcastHjPlan = buildBroadcastHashJoinPlan(rightJn, 
leftJn, hashJoinExpr, null);
+            bcastHjPlan = buildBroadcastHashJoinPlan(leftJn, rightJn, 
leftPlan, rightPlan, hashJoinExpr, null);
+            if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                commutativeBcastHjPlan =
+                        buildBroadcastHashJoinPlan(rightJn, leftJn, rightPlan, 
leftPlan, hashJoinExpr, null);
             }
-            nljPlan = buildNLJoinPlan(leftJn, rightJn, nestedLoopJoinExpr, 
null);
-            if (!joinEnum.forceJoinOrderMode) {
-                commutativeNljPlan = buildNLJoinPlan(rightJn, leftJn, 
nestedLoopJoinExpr, null);
+            nljPlan = buildNLJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
nestedLoopJoinExpr, null);
+            if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                commutativeNljPlan = buildNLJoinPlan(rightJn, leftJn, 
rightPlan, leftPlan, nestedLoopJoinExpr, null);
             }
-            cpPlan = buildCPJoinPlan(leftJn, rightJn, hashJoinExpr, 
nestedLoopJoinExpr);
-            if (!joinEnum.forceJoinOrderMode) {
-                commutativeCpPlan = buildCPJoinPlan(rightJn, leftJn, 
hashJoinExpr, nestedLoopJoinExpr);
+            cpPlan = buildCPJoinPlan(leftJn, rightJn, leftPlan, rightPlan, 
hashJoinExpr, nestedLoopJoinExpr);
+            if (!joinEnum.forceJoinOrderMode || !joinEnum.cboPruningMode) {
+                commutativeCpPlan =
+                        buildCPJoinPlan(rightJn, leftJn, rightPlan, leftPlan, 
hashJoinExpr, nestedLoopJoinExpr);
             }
         }

@@ -1110,21 +1153,22 @@
                 && commutativeBcastHjPlan == PlanNode.NO_PLAN && nljPlan == 
PlanNode.NO_PLAN
                 && commutativeNljPlan == PlanNode.NO_PLAN && cpPlan == 
PlanNode.NO_PLAN
                 && commutativeCpPlan == PlanNode.NO_PLAN) {
-            return new Pair<>(PlanNode.NO_PLAN, noJoinCost);
+            return;
         }

         //Reset as these might have changed when we tried the commutative 
joins.
         this.leftJn = leftJn;
         this.rightJn = rightJn;

-        PlanNode cheapestPlan = findCheapestPlan();
-        this.cheapestPlanCost = cheapestPlan.totalCost;
-        this.cheapestPlanIndex = cheapestPlan.allPlansIndex;
-
-        return new Pair<>(this.cheapestPlanIndex, this.cheapestPlanCost);
+        return;
     }

     private PlanNode findCheapestPlan() {
+        if (!joinEnum.cboPruningMode) {
+            // If pruning is off, just return something.
+            return joinEnum.allPlans.get(planIndexesArray.get(0));
+        }
+
         List<PlanNode> allPlans = joinEnum.allPlans;
         ICost cheapestCost = joinEnum.getCostHandle().maxCost();
         PlanNode cheapestPlanNode = null;
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
index 01f9509..3136258 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
@@ -119,6 +119,10 @@
                 STRING,
                 AlgebricksConfig.QUERY_PLAN_SHAPE_DEFAULT,
                 "Set the mode for forcing the shape of the query plan"),
+        COMPILER_CBOPRUNING(
+                BOOLEAN,
+                AlgebricksConfig.CBO_PRUNING_DEFAULT,
+                "Set the mode for pruning during join and plan enumeration in 
the optimizer"),
         COMPILER_COLUMN_FILTER(
                 BOOLEAN,
                 AlgebricksConfig.COLUMN_FILTER_DEFAULT,
@@ -156,7 +160,7 @@

         @Override
         public boolean hidden() {
-            return this == COMPILER_EXTERNALSCANMEMORY || this == 
COMPILER_CBOTEST;
+            return this == COMPILER_EXTERNALSCANMEMORY || this == 
COMPILER_CBOTEST || this == COMPILER_CBOPRUNING;
         }
     }

@@ -202,6 +206,8 @@
 
     public static final String COMPILER_QUERY_PLAN_SHAPE_KEY = 
Option.COMPILER_QUERYPLANSHAPE.ini();

+    public static final String COMPILER_CBO_PRUNING_KEY = 
Option.COMPILER_CBOPRUNING.ini();
+
     public static final String COMPILER_COLUMN_FILTER_KEY = 
Option.COMPILER_COLUMN_FILTER.ini();

     public static final int COMPILER_PARALLELISM_AS_STORAGE = 0;
@@ -303,6 +309,10 @@
         return queryPlanShapeMode;
     }

+    public boolean getCBOPruningMode() {
+        return accessor.getBoolean(Option.COMPILER_CBOPRUNING);
+    }
+
     public boolean isColumnFilter() {
         return accessor.getBoolean(Option.COMPILER_COLUMN_FILTER);
     }
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/OptimizationConfUtil.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/OptimizationConfUtil.java
index c103b50..a9ab8d6 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/OptimizationConfUtil.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/OptimizationConfUtil.java
@@ -87,6 +87,8 @@
                 compilerProperties.getForceJoinOrderMode());
         String queryPlanShape = getString(querySpecificConfig, 
CompilerProperties.COMPILER_QUERY_PLAN_SHAPE_KEY,
                 compilerProperties.getQueryPlanShapeMode());
+        boolean cboPruning = getBoolean(querySpecificConfig, 
CompilerProperties.COMPILER_CBO_PRUNING_KEY,
+                compilerProperties.getCBOPruningMode());
         boolean columnFilter = getBoolean(querySpecificConfig, 
CompilerProperties.COMPILER_COLUMN_FILTER_KEY,
                 compilerProperties.isColumnFilter());

@@ -112,6 +114,7 @@
         physOptConf.setCBOTestMode(cboTest);
         physOptConf.setForceJoinOrderMode(forceJoinOrder);
         physOptConf.setQueryPlanShapeMode(queryPlanShape);
+        physOptConf.setCBOPruningMode(cboPruning);
         physOptConf.setColumnFilter(columnFilter);
         return physOptConf;
     }
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
index 74f4447..91c2533 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
@@ -39,6 +39,7 @@
     public static final boolean CBO_TEST_DEFAULT = false;
     public static final boolean FORCE_JOIN_ORDER_DEFAULT = false;
     public static final String QUERY_PLAN_SHAPE_ZIGZAG = "zigzag";
+    public static final boolean CBO_PRUNING_DEFAULT = true;
     public static final String QUERY_PLAN_SHAPE_LEFTDEEP = "leftdeep";
     public static final String QUERY_PLAN_SHAPE_RIGHTDEEP = "rightdeep";
     public static final String QUERY_PLAN_SHAPE_DEFAULT = 
QUERY_PLAN_SHAPE_ZIGZAG;
diff --git 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/PhysicalOptimizationConfig.java
 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/PhysicalOptimizationConfig.java
index 3e51a80..b77e704 100644
--- 
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/PhysicalOptimizationConfig.java
+++ 
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/rewriter/base/PhysicalOptimizationConfig.java
@@ -52,6 +52,7 @@
     private static final String CBO_TEST = "CBO_TEST";
     private static final String FORCE_JOIN_ORDER = "FORCE_JOIN_ORDER";
     private static final String QUERY_PLAN_SHAPE = "QUERY_PLAN_SHAPE";
+    private static final String CBO_PRUNING = "CBO_PRUNING";
     private static final String COLUMN_FILTER = "COLUMN_FILTER";

     private final Properties properties = new Properties();
@@ -267,6 +268,10 @@
         return queryPlanShapeMode;
     }

+    public boolean getCBOPruningMode() {
+        return getBoolean(CBO_PRUNING, AlgebricksConfig.CBO_PRUNING_DEFAULT);
+    }
+
     public void setCBOMode(boolean cbo) {
         setBoolean(CBO, cbo);
     }
@@ -283,6 +288,10 @@
         setString(QUERY_PLAN_SHAPE, queryPlanShape);
     }

+    public void setCBOPruningMode(boolean cboPruning) {
+        setBoolean(CBO_PRUNING, cboPruning);
+    }
+
     public boolean isBatchLookupEnabled() {
         return getBoolean(BATCH_LOOKUP, AlgebricksConfig.BATCH_LOOKUP_DEFAULT);
     }

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17550
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: Ie99c7310ebfca075f3211f32195fb2ad5df7c470
Gerrit-Change-Number: 17550
Gerrit-PatchSet: 1
Gerrit-Owner: Vijay Sarathy <[email protected]>
Gerrit-MessageType: newchange

Reply via email to