This is an automated email from the ASF dual-hosted git repository.

alsuliman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 52ad6d5240 [ASTERIXDB-3571][COMP] Infer selection predicates from join 
predicates
52ad6d5240 is described below

commit 52ad6d52409ef22345fbbda8f876c7336458705b
Author: murali4104 <[email protected]>
AuthorDate: Tue Mar 11 15:09:33 2025 -0700

    [ASTERIXDB-3571][COMP] Infer selection predicates from join predicates
    
    Ext-Ref: MB-65670
    
    Change-Id: Iac01b5eba1b35d66e50d86205ddef05fb86c334a
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19489
    Integration-Tests: Jenkins <[email protected]>
    Reviewed-by: <[email protected]>
    Reviewed-by: <[email protected]>
    Reviewed-by: Peeyush Gupta <[email protected]>
    Tested-by: Jenkins <[email protected]>
---
 .../optimizer/rules/cbo/EnumerateJoinsRule.java    |   3 +
 .../asterix/optimizer/rules/cbo/JoinEnum.java      | 148 ++++++++++++-
 .../test/runtime/SqlppAnalyzedExecutionTest.java   |   2 +-
 .../optimizerts/results_cbo/ch2/ch2_q8.plan        | 234 +++++++++++----------
 .../leftouterjoin/query-ASTERIXDB-2857.plan        |  84 ++++----
 .../inverted-index-join/ngram-contains_01_ps.plan  | 130 ++++++------
 .../inverted-index-join/ngram-contains_02_ps.plan  | 130 ++++++------
 .../inverted-index-join/ngram-contains_01_ps.plan  | 130 ++++++------
 .../hash-join-with-redundant-variable.06.plan      |  68 +++---
 9 files changed, 555 insertions(+), 374 deletions(-)

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 97020032b4..7a3b2995ee 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
@@ -465,8 +465,11 @@ public class EnumerateJoinsRule implements 
IAlgebraicRewriteRule {
                 DataSourceScanOperator fakeDs = (DataSourceScanOperator) 
truncateInput(leafInput);
                 fakeLeafInputsMap.put(fakeDs, true);
                 LogicalVariable var1 = fakeDs.getVariables().get(0);
+                varLeafInputIds.put(var1, j);
                 MutableObject<ILogicalOperator> q = new 
MutableObject<>(fakeDs);
                 LogicalVariable var2 = modify(q.getValue(), context); // so as 
to make it fake, remove teh original variables
+                varLeafInputIds.put(var2, j + 1); // this InputId has to be 
different from j, which is a real leaf input.
+                joinEnum.varLeafInputIds = varLeafInputIds; // this is needed 
for making new join expressions
                 ILogicalExpression expr = joinEnum.makeNewEQJoinExpr(var1, 
var2);
                 foj = new LeftOuterJoinOperator(new MutableObject<>(expr), new 
MutableObject<>(leftChild), q,
                         ConstantExpression.MISSING.getValue());
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 125ba8cbab..e77e06672b 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
@@ -71,6 +71,7 @@ import 
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCall
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
+import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
@@ -296,6 +297,8 @@ public class JoinEnum {
 
         if (andExpr.getArguments().size() == 1) {
             return andExpr.getArguments().get(0).getValue(); // remove the AND 
if there is only one argument
+        } else if (andExpr.getArguments().size() > 1) {
+            return null; // the nested loops code expects only one predicate 
of the type R.a op S.a
         }
         return andExpr;
     }
@@ -452,8 +455,8 @@ public class JoinEnum {
     }
 
     // This finds all the join Conditions in the whole query. This is a global 
list of all join predicates.
-    // It also fills in the dataset Bits for each join predicate.
-    private void findJoinConditionsAndAssignSels() throws AlgebricksException {
+    // It also fills in the dataset Bits for each join predicate. Add 
Transitive Join Predicates also.
+    private void findJoinConditionsAndDoTC() throws AlgebricksException {
         List<Mutable<ILogicalExpression>> conjs = new ArrayList<>();
         for (JoinOperator jOp : allJoinOps) {
             AbstractBinaryJoinOperator joinOp = jOp.getAbstractJoinOp();
@@ -488,7 +491,7 @@ public class JoinEnum {
                 }
             }
         }
-        addTCPreds(); // transitive close of join predicates
+        addTCJoinPreds(); // transitive close of join predicates
         // now patch up any join conditions that have variables referenced in 
any internal assign statements.
         List<LogicalVariable> usedVars = new ArrayList<>();
         List<AssignOperator> erase = new ArrayList<>();
@@ -506,7 +509,6 @@ public class JoinEnum {
                     }
                 }
             }
-            jc.selectivity = 
stats.getSelectivityFromAnnotationMain(jc.joinCondition, true, false, 
jc.joinOp);
         }
         for (int i = erase.size() - 1; i >= 0; i--) {
             assignOps.remove(erase.get(i));
@@ -544,7 +546,7 @@ public class JoinEnum {
     }
 
     // transitive close of join predicates; add only if they are not already 
present; user may have added them in the query
-    private void addTCPreds() {
+    private void addTCJoinPreds() {
         boolean changes = true;
         while (changes) {
             changes = false;
@@ -592,6 +594,9 @@ public class JoinEnum {
     }
 
     protected ILogicalExpression makeNewEQJoinExpr(LogicalVariable var1, 
LogicalVariable var2) {
+        if (varLeafInputIds.get(var1) == varLeafInputIds.get(var2)) {
+            return null; // must be from different datasets to make a join 
expression
+        }
         List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
         VariableReferenceExpression e1 = new VariableReferenceExpression(var1);
         arguments.add(new MutableObject<>(e1));
@@ -1162,8 +1167,12 @@ public class JoinEnum {
     // Find the join conditions. Assign selectivities to the join conditions 
from any user provided annotation hints.
     // If there are no annotation hints, use samples to find the selectivities 
of the single table predicates
     // found inside of complex join predicates (as in q7). A lot of extra code 
has gone into making q7 work.
-    private void findJoinConditions() throws AlgebricksException {
-        findJoinConditionsAndAssignSels();
+    // With this routine we can compute the cardinality of the join predicate 
between n1 and n2 correctly (2 in this case).
+    //The predicate in Q7 between n1 and n2 is
+    //(n1.name = INDIA AND n2.name = JAPAN) OR
+    //(n1.name = JAPAN AND n2.name = INDIA)
+    // So this appears as a join predicate but we have to compute the 
selectivities of the selection predicates inside the join. MESSY
+    private void findSelectionPredsInsideJoins() throws AlgebricksException {
         // for all the singleVarExprs, we need to issue a sample query. These 
exprs did not get assigned a selectivity.
         for (ILogicalExpression exp : this.singleDatasetPreds) {
             if (isPredicateCardinalityAnnotationPresent(exp)) {
@@ -1176,7 +1185,7 @@ public class JoinEnum {
                 ILogicalOperator leafInput = findLeafInput(vars);
                 SelectOperator selOp;
                 if 
(leafInput.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
-                    selOp = (SelectOperator) 
getStatsHandle().findSelectOpWithExpr(leafInput, exp);
+                    selOp = getStatsHandle().findSelectOpWithExpr(leafInput, 
exp);
                     if (selOp == null) {
                         selOp = (SelectOperator) leafInput;
                     }
@@ -1196,7 +1205,7 @@ public class JoinEnum {
             }
         }
 
-        if (this.singleDatasetPreds.size() > 0) { // We did not have 
selectivities for these before. Now we do.
+        if (this.singleDatasetPreds.size() > 0) {
             for (JoinCondition jc : joinConditions) {
                 // we may be repeating some work here, but that is ok. This 
will rarely happen (happens in q7 tpch)
                 double sel = 
stats.getSelectivityFromAnnotationMain(jc.getJoinCondition(), false, true, 
null);
@@ -1214,6 +1223,8 @@ public class JoinEnum {
         localJoinOp = new InnerJoinOperator(new 
MutableObject<>(ConstantExpression.TRUE),
                 new MutableObject<>(dummyInput), new 
MutableObject<>(dummyInput));
 
+        findJoinConditionsAndDoTC();
+        addTCSelectionPredicates();
         int lastBaseLevelJnNum = enumerateBaseLevelJoinNodes();
         if (lastBaseLevelJnNum == PlanNode.NO_PLAN) {
             return PlanNode.NO_PLAN;
@@ -1224,7 +1235,11 @@ public class JoinEnum {
             EnumerateJoinsRule.printPlan(pp, op, "Original Whole plan in JN 
1");
         }
 
-        findJoinConditions();
+        for (JoinCondition jc : joinConditions) {
+            jc.selectivity = 
stats.getSelectivityFromAnnotationMain(jc.joinCondition, true, false, 
jc.joinOp);
+        }
+
+        findSelectionPredsInsideJoins(); // This was added to make TPCH Q7 
work.
         findIfJoinGraphIsConnected();
 
         if (LOGGER.isTraceEnabled()) {
@@ -1243,6 +1258,119 @@ public class JoinEnum {
         return lastJn.cheapestPlanIndex;
     }
 
+    // R.a = S.a and R.a op operand ==> S.a op operand
+    private void addTCSelectionPredicates() throws AlgebricksException {
+        List<SelectOperator> existingSelOps = new ArrayList<>();
+        for (ILogicalOperator leafInput : this.leafInputs) {
+            ILogicalOperator li = leafInput.getInputs().get(0).getValue(); // 
skip the true on the top
+            List<SelectOperator> selOps = findAllSimpleSelOps(li); // variable 
op operand
+            existingSelOps.addAll(selOps);
+        }
+        addTCSelectionPredicatesHelper(existingSelOps);
+    }
+
+    private void addTCSelectionPredicatesHelper(List<SelectOperator> 
existingSelOps) throws AlgebricksException {
+        for (SelectOperator selOp : existingSelOps) {
+            AbstractFunctionCallExpression exp = 
(AbstractFunctionCallExpression) selOp.getCondition().getValue();
+            Mutable<ILogicalExpression> x = exp.getArguments().get(0);
+            VariableReferenceExpression varRef = (VariableReferenceExpression) 
x.getValue();
+            LogicalVariable var = varRef.getVariableReference();
+            SelectOperator newSelOp;
+            List<JoinCondition> jcs = findVarinJoinPreds(var);
+            for (JoinCondition jc : jcs) { // join predicate can be R.a = S.a 
or S.a = R.a. Check for both cases
+                if (var == jc.usedVars.get(0)) { // R.a
+                    newSelOp = makeNewSelOper(existingSelOps, 
jc.usedVars.get(1), // == S.a
+                            ((AbstractFunctionCallExpression) 
selOp.getCondition().getValue()).getFunctionInfo(), // op
+                            exp.getArguments().get(1)); // operand
+                    if (newSelOp != null) { // does not already exist
+                        addSelOpToLeafInput(jc.usedVars.get(1), newSelOp);
+                    }
+                } else if (var == jc.usedVars.get(1)) { // R.a
+                    newSelOp = makeNewSelOper(existingSelOps, 
jc.usedVars.get(0), // == S.a
+                            ((AbstractFunctionCallExpression) 
selOp.getCondition().getValue()).getFunctionInfo(), // op
+                            exp.getArguments().get(1)); // operand
+                    if (newSelOp != null) {
+                        addSelOpToLeafInput(jc.usedVars.get(0), newSelOp);
+                    }
+                }
+            }
+        }
+    }
+
+    private SelectOperator makeNewSelOper(List<SelectOperator> existingSelOps, 
LogicalVariable var, IFunctionInfo tag,
+            Mutable<ILogicalExpression> arg) throws AlgebricksException {
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
+        VariableReferenceExpression e1 = new VariableReferenceExpression(var);
+        arguments.add(new MutableObject<>(e1)); // S.a
+        arguments.add(new MutableObject<>(arg.getValue())); // this will be 
the operand
+        ScalarFunctionCallExpression expr = new 
ScalarFunctionCallExpression(tag, arguments); //S.a op operand
+        SelectOperator newsel = new SelectOperator(new MutableObject<>(expr), 
null, null);
+        if (newSelNotPresent(newsel, existingSelOps)) {
+            LOGGER.info("adding newsel " + newsel.getCondition());
+            return newsel; // add since it does not exist
+        } else {
+            return null; // already exists, no need to add again
+        }
+    }
+
+    private boolean newSelNotPresent(SelectOperator newsel, 
List<SelectOperator> existingSelOps) {
+        for (SelectOperator existingSelOp : existingSelOps) {
+            if (newsel.getCondition().equals(existingSelOp.getCondition())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void addSelOpToLeafInput(LogicalVariable var, SelectOperator 
newSelOp) throws AlgebricksException {
+        int l = varLeafInputIds.get(var); // get the corresponding leafInput 
using the map
+        ILogicalOperator parent = leafInputs.get(l - 1);
+        ILogicalOperator child = parent.getInputs().get(0).getValue();
+        parent.getInputs().get(0).setValue(newSelOp);
+        newSelOp.getInputs().add(new MutableObject<>(child));
+        optCtx.computeAndSetTypeEnvironmentForOperator(newSelOp);
+    }
+
+    private List<JoinCondition> findVarinJoinPreds(LogicalVariable var) {
+        List<JoinCondition> jcs = new ArrayList<>();
+        for (JoinCondition jc : joinConditions) {
+            if (jc.usedVars != null && jc.usedVars.contains(var)) { // this 
will only search inner join predicates
+                jcs.add(jc);
+            }
+        }
+        return jcs;
+    }
+
+    private List<SelectOperator> findAllSimpleSelOps(ILogicalOperator li) {
+        List<SelectOperator> selOps = new ArrayList<>();
+        while (li != null && li.getOperatorTag() != 
LogicalOperatorTag.EMPTYTUPLESOURCE) {
+            if (li.getOperatorTag().equals(LogicalOperatorTag.SELECT)) {
+                SelectOperator selOp = (SelectOperator) li;
+                ILogicalExpression condition = selOp.getCondition().getValue();
+                if (simpleCondition(condition)) {
+                    selOps.add(selOp);
+                }
+            }
+            li = li.getInputs().get(0).getValue();
+        }
+        return selOps;
+    }
+
+    private boolean simpleCondition(ILogicalExpression condition) {
+        if (condition.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+            AbstractFunctionCallExpression exp = 
(AbstractFunctionCallExpression) condition;
+            if (exp.getArguments().size() == 2) {
+                Mutable<ILogicalExpression> arg0 = exp.getArguments().get(0);
+                Mutable<ILogicalExpression> arg1 = exp.getArguments().get(1);
+                if (arg0.getValue().getExpressionTag() == 
LogicalExpressionTag.VARIABLE
+                        && arg1.getValue().getExpressionTag() == 
LogicalExpressionTag.CONSTANT) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private String dumpJoinNodes(int numJoinNodes) {
         StringBuilder sb = new StringBuilder(128);
         sb.append(LocalDateTime.now());
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
index 76347a17ae..2c5f247e46 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
@@ -46,7 +46,7 @@ public class SqlppAnalyzedExecutionTest {
     private final String[] denyList = { "synonym: synonym-01", "ddl: 
analyze-dataset-1", "misc: dump_index",
             "array-index: composite-index-queries", "filters: upsert", 
"column: analyze-dataset",
             "column: filter/boolean", "column: filter/sql-compat", "ddl: 
analyze-dataset-with-indexes",
-            "warnings: cardinality-hint-warning" };
+            "warnings: cardinality-hint-warning", "comparison: 
incomparable_types" };
 
     @BeforeClass
     public static void setUp() throws Exception {
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q8.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q8.plan
index c663bd125e..0b94e965bf 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q8.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q8.plan
@@ -1,222 +1,224 @@
-distribute result [$$293] [cardinality: 9.223372036854776E16, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
+distribute result [$$293] [cardinality: 9.223372036854776E16, doc-size: -8.0, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+  exchange [cardinality: 9.223372036854776E16, doc-size: -8.0, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$293] <- [{"l_year": $#1, "mkt_share": 
round(numeric-divide($$322, $$323), 2)}] project: [$$293] [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 9.223372036854776E16]
+    assign [$$293] <- [{"l_year": $#1, "mkt_share": 
round(numeric-divide($$322, $$323), 2)}] project: [$$293] [cardinality: 
9.223372036854776E16, doc-size: -8.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
     -- ASSIGN  |PARTITIONED|
-      exchange [cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+      exchange [cardinality: 9.223372036854776E16, doc-size: -8.0, op-cost: 
0.0, total-cost: 9.223372036854776E16]
       -- SORT_MERGE_EXCHANGE [$#1(ASC) ]  |PARTITIONED|
         group by ([$#1 := $$351]) decor ([]) {
-                  aggregate [$$322, $$323] <- [agg-global-sql-sum($$349), 
agg-global-sql-sum($$350)]
+                  aggregate [$$322, $$323] <- [agg-global-sql-sum($$349), 
agg-global-sql-sum($$350)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                   -- AGGREGATE  |LOCAL|
-                    nested tuple source
+                    nested tuple source [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
                     -- NESTED_TUPLE_SOURCE  |LOCAL|
-               } [cardinality: 0.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+               } [cardinality: 9.223372036854776E16, doc-size: -8.0, op-cost: 
0.0, total-cost: 9.223372036854776E16]
         -- SORT_GROUP_BY[$$351]  |PARTITIONED|
-          exchange [cardinality: 9.223372036854776E16, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
+          exchange [cardinality: 9.223372036854776E16, doc-size: -8.0, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
           -- HASH_PARTITION_EXCHANGE [$$351]  |PARTITIONED|
             group by ([$$351 := $$294]) decor ([]) {
-                      aggregate [$$349, $$350] <- 
[agg-local-sql-sum(switch-case(true, eq($$342, "Germany"), $$335, 0)), 
agg-local-sql-sum($$335)]
+                      aggregate [$$349, $$350] <- 
[agg-local-sql-sum(switch-case(true, eq($$342, "Germany"), $$335, 0)), 
agg-local-sql-sum($$335)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
-                        nested tuple source
+                        nested tuple source [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   } [cardinality: 0.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+                   } [cardinality: 9.223372036854776E16, doc-size: -8.0, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
             -- SORT_GROUP_BY[$$294]  |PARTITIONED|
-              exchange [cardinality: 9.223372036854776E16, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
+              exchange [cardinality: 9.223372036854776E16, doc-size: -8.0, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                assign [$$294] <- [get-year(date($$305))] project: [$$342, 
$$335, $$294] [cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+                assign [$$294] <- [get-year(date($$305))] project: [$$342, 
$$335, $$294] [cardinality: 9.223372036854776E16, doc-size: -8.0, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
                 -- ASSIGN  |PARTITIONED|
-                  project ([$$335, $$305, $$342]) [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 9.223372036854776E16]
+                  project ([$$335, $$305, $$342]) [cardinality: 
9.223372036854776E16, doc-size: -8.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
                   -- STREAM_PROJECT  |PARTITIONED|
-                    exchange [cardinality: 9.223372036854776E16, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
+                    exchange [cardinality: 9.223372036854776E16, doc-size: 
-8.0, op-cost: 0.0, total-cost: 9.223372036854776E16]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      join (eq($$325, $$326)) [cardinality: 
9.223372036854776E16, op-cost: 9.223372036854776E16, total-cost: 
9.223372036854776E16]
+                      join (eq($$325, $$326)) [cardinality: 
9.223372036854776E16, doc-size: -8.0, op-cost: 9.223372036854776E16, 
total-cost: 9.223372036854776E16]
                       -- HYBRID_HASH_JOIN [$$325][$$326]  |PARTITIONED|
-                        exchange [cardinality: 9.223372036854776E16, op-cost: 
0.0, total-cost: 9.223372036854776E16]
+                        exchange [cardinality: 9.223372036854776E16, doc-size: 
-7.0, op-cost: 0.0, total-cost: 9.223372036854776E16]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          project ([$$335, $$305, $$325]) [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 9.223372036854776E16]
+                          project ([$$335, $$305, $$325]) [cardinality: 
9.223372036854776E16, doc-size: -7.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
                           -- STREAM_PROJECT  |PARTITIONED|
-                            exchange [cardinality: 9.223372036854776E16, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
+                            exchange [cardinality: 9.223372036854776E16, 
doc-size: -7.0, op-cost: 0.0, total-cost: 9.223372036854776E16]
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              join (eq($$348, $$341)) [cardinality: 
9.223372036854776E16, op-cost: 9.223372036854776E16, total-cost: 
9.223372036854776E16]
+                              join (eq($$348, $$341)) [cardinality: 
9.223372036854776E16, doc-size: -7.0, op-cost: 9.223372036854776E16, 
total-cost: 9.223372036854776E16]
                               -- HYBRID_HASH_JOIN [$$348][$$341]  |PARTITIONED|
-                                exchange [cardinality: 9.223372036854776E16, 
op-cost: 0.0, total-cost: 9.223372036854776E16]
+                                exchange [cardinality: 9.223372036854776E16, 
doc-size: -6.0, op-cost: 0.0, total-cost: 9.223372036854776E16]
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                  assign [$$348] <- 
[numeric-mod(numeric-multiply($$295, $$296), 10000)] project: [$$335, $$305, 
$$348] [cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+                                  assign [$$348] <- 
[numeric-mod(numeric-multiply($$295, $$296), 10000)] project: [$$335, $$305, 
$$348] [cardinality: 9.223372036854776E16, doc-size: -6.0, op-cost: 0.0, 
total-cost: 9.223372036854776E16]
                                   -- ASSIGN  |PARTITIONED|
-                                    project ([$$335, $$305, $$295, $$296]) 
[cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
9.223372036854776E16]
+                                    project ([$$335, $$305, $$295, $$296]) 
[cardinality: 9.223372036854776E16, doc-size: -6.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
                                     -- STREAM_PROJECT  |PARTITIONED|
-                                      exchange [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 9.223372036854776E16]
+                                      exchange [cardinality: 
9.223372036854776E16, doc-size: -6.0, op-cost: 0.0, total-cost: 
9.223372036854776E16]
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        join (eq($$308, $$309)) [cardinality: 
9.223372036854776E16, op-cost: 9.223372036854776E16, total-cost: 
9.223372036854776E16]
+                                        join (eq($$308, $$309)) [cardinality: 
9.223372036854776E16, doc-size: -6.0, op-cost: 9.223372036854776E16, 
total-cost: 9.223372036854776E16]
                                         -- HYBRID_HASH_JOIN [$$308][$$309]  
|PARTITIONED|
-                                          exchange [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 5.00025E11]
+                                          exchange [cardinality: 
9.223372036854776E16, doc-size: -5.0, op-cost: 0.0, total-cost: 5.00025E11]
                                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                            project ([$$335, $$305, $$295, 
$$296, $$308]) [cardinality: 9.223372036854776E16, op-cost: 0.0, total-cost: 
5.00025E11]
+                                            project ([$$335, $$305, $$295, 
$$296, $$308]) [cardinality: 9.223372036854776E16, doc-size: -5.0, op-cost: 
0.0, total-cost: 5.00025E11]
                                             -- STREAM_PROJECT  |PARTITIONED|
-                                              exchange [cardinality: 
9.223372036854776E16, op-cost: 0.0, total-cost: 5.00025E11]
+                                              exchange [cardinality: 
9.223372036854776E16, doc-size: -5.0, op-cost: 0.0, total-cost: 5.00025E11]
                                               -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                join (eq($$331, $$311)) 
[cardinality: 9.223372036854776E16, op-cost: 5.00004E11, total-cost: 5.00025E11]
+                                                join (eq($$331, $$311)) 
[cardinality: 9.223372036854776E16, doc-size: -5.0, op-cost: 5.00004E11, 
total-cost: 5.00025E11]
                                                 -- HYBRID_HASH_JOIN 
[$$311][$$331]  |PARTITIONED|
-                                                  exchange [cardinality: 
5.0E11, op-cost: 0.0, total-cost: 1.6E7]
+                                                  exchange [cardinality: 
5.0E11, doc-size: -4.0, op-cost: 0.0, total-cost: 1.6E7]
                                                   -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                    project ([$$335, $$305, 
$$295, $$296, $$311]) [cardinality: 5.0E11, op-cost: 0.0, total-cost: 1.6E7]
+                                                    project ([$$335, $$305, 
$$295, $$296, $$311]) [cardinality: 5.0E11, doc-size: -4.0, op-cost: 0.0, 
total-cost: 1.6E7]
                                                     -- STREAM_PROJECT  
|PARTITIONED|
-                                                      exchange [cardinality: 
5.0E11, op-cost: 0.0, total-cost: 1.6E7]
+                                                      exchange [cardinality: 
5.0E11, doc-size: -4.0, op-cost: 0.0, total-cost: 1.6E7]
                                                       -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                        join (eq($$324, 
$$306)) [cardinality: 5.0E11, op-cost: 2000000.0, total-cost: 1.6E7]
+                                                        join (eq($$324, 
$$306)) [cardinality: 5.0E11, doc-size: -4.0, op-cost: 2000000.0, total-cost: 
1.6E7]
                                                         -- HYBRID_HASH_JOIN 
[$$306][$$324]  |PARTITIONED|
-                                                          exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1.2E7]
+                                                          exchange 
[cardinality: 1000000.0, doc-size: -3.0, op-cost: 0.0, total-cost: 1.1E7]
                                                           -- 
HASH_PARTITION_EXCHANGE [$$306]  |PARTITIONED|
-                                                            project ([$$335, 
$$305, $$295, $$296, $$311, $$306]) [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1.1E7]
+                                                            project ([$$335, 
$$305, $$295, $$296, $$311, $$306]) [cardinality: 1000000.0, doc-size: -3.0, 
op-cost: 0.0, total-cost: 1.1E7]
                                                             -- STREAM_PROJECT  
|PARTITIONED|
-                                                              exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1.2E7]
+                                                              exchange 
[cardinality: 1000000.0, doc-size: -3.0, op-cost: 0.0, total-cost: 1.1E7]
                                                               -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                join 
(and(eq($$333, $$313), eq($$334, $$315), eq($$332, $$317))) [cardinality: 
1000000.0, op-cost: 2000000.0, total-cost: 1.1E7]
+                                                                join 
(and(eq($$333, $$313), eq($$334, $$315), eq($$332, $$317))) [cardinality: 
1000000.0, doc-size: -3.0, op-cost: 2000000.0, total-cost: 1.1E7]
                                                                 -- 
HYBRID_HASH_JOIN [$$313, $$315, $$317][$$333, $$334, $$332]  |PARTITIONED|
-                                                                  exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 7000000.0]
+                                                                  exchange 
[cardinality: 1000000.0, doc-size: -2.0, op-cost: 0.0, total-cost: 6000000.0]
                                                                   -- 
HASH_PARTITION_EXCHANGE [$$313, $$315, $$317]  |PARTITIONED|
-                                                                    project 
([$$335, $$305, $$295, $$296, $$306, $$313, $$315, $$317]) [cardinality: 
1000000.0, op-cost: 0.0, total-cost: 6000000.0]
+                                                                    project 
([$$335, $$305, $$295, $$296, $$306, $$313, $$315, $$317]) [cardinality: 
1000000.0, doc-size: -2.0, op-cost: 0.0, total-cost: 6000000.0]
                                                                     -- 
STREAM_PROJECT  |PARTITIONED|
-                                                                      exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 7000000.0]
+                                                                      exchange 
[cardinality: 1000000.0, doc-size: -2.0, op-cost: 0.0, total-cost: 6000000.0]
                                                                       -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                        join 
(and(eq($$306, $$296), eq($$336, $$295))) [cardinality: 1000000.0, op-cost: 
2000000.0, total-cost: 6000000.0]
+                                                                        join 
(and(eq($$306, $$296), eq($$336, $$295))) [cardinality: 1000000.0, doc-size: 
-2.0, op-cost: 2000000.0, total-cost: 6000000.0]
                                                                         -- 
HYBRID_HASH_JOIN [$$296, $$295][$$306, $$336]  |PARTITIONED|
-                                                                          
exchange [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                                          
exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                           -- 
HASH_PARTITION_EXCHANGE [$$296, $$295]  |PARTITIONED|
-                                                                            
assign [$$296, $$295] <- [$$s.getField("s_i_id"), $$s.getField("s_w_id")] 
project: [$$295, $$296] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
-                                                                            -- 
ASSIGN  |PARTITIONED|
-                                                                              
project ([$$s]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
-                                                                              
-- STREAM_PROJECT  |PARTITIONED|
-                                                                               
 exchange [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
-                                                                               
 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                               
   data-scan []<-[$$297, $$s] <- test.stock [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 1000000.0]
-                                                                               
   -- DATASOURCE_SCAN  |PARTITIONED|
-                                                                               
     exchange
-                                                                               
     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                               
       empty-tuple-source
-                                                                               
       -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                                                          
exchange [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                                            
select (lt($$296, 1000)) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                                                            -- 
STREAM_SELECT  |PARTITIONED|
+                                                                              
assign [$$296, $$295] <- [$$s.getField("s_i_id"), $$s.getField("s_w_id")] 
project: [$$296, $$295] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                                                              
-- ASSIGN  |PARTITIONED|
+                                                                               
 project ([$$s]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                                                               
 -- STREAM_PROJECT  |PARTITIONED|
+                                                                               
   exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                                                               
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                                                               
     data-scan []<-[$$297, $$s] <- test.stock [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                                               
     -- DATASOURCE_SCAN  |PARTITIONED|
+                                                                               
       exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                                                               
       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                                                               
         empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
+                                                                               
         -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                                                                          
exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                           -- 
HASH_PARTITION_EXCHANGE [$$306, $$336]  |PARTITIONED|
-                                                                            
select (lt($$306, 1000)) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                                                            
select (lt($$306, 1000)) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                                                             -- 
STREAM_SELECT  |PARTITIONED|
-                                                                              
assign [$$336, $$335, $$306] <- [$$ol.getField("ol_supply_w_id"), 
$$ol.getField("ol_amount"), $$ol.getField("ol_i_id")] project: [$$317, $$315, 
$$313, $$305, $$336, $$335, $$306] [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                                                              
assign [$$336, $$335, $$306] <- [$$ol.getField("ol_supply_w_id"), 
$$ol.getField("ol_amount"), $$ol.getField("ol_i_id")] project: [$$317, $$315, 
$$313, $$305, $$336, $$335, $$306] [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
                                                                               
-- ASSIGN  |PARTITIONED|
-                                                                               
 unnest $$ol <- scan-collection($$327) project: [$$317, $$315, $$313, $$305, 
$$ol] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                                               
 unnest $$ol <- scan-collection($$327) project: [$$317, $$315, $$313, $$305, 
$$ol] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                                
 -- UNNEST  |PARTITIONED|
-                                                                               
   select (and(le($$305, "2018-12-31 00:00:00.000000"), ge($$305, "2017-01-01 
00:00:00.000000")))
+                                                                               
   select (and(le($$305, "2018-12-31 00:00:00.000000"), ge($$305, "2017-01-01 
00:00:00.000000"))) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                                                                
   -- STREAM_SELECT  |PARTITIONED|
-                                                                               
     assign [$$317, $$315, $$313, $$305, $$327] <- [$$o.getField("o_c_id"), 
$$o.getField("o_d_id"), $$o.getField("o_w_id"), $$o.getField("o_entry_d"), 
$$o.getField("o_orderline")] project: [$$317, $$315, $$313, $$305, $$327] 
[cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                                               
     assign [$$317, $$315, $$313, $$305, $$327] <- [$$o.getField("o_c_id"), 
$$o.getField("o_d_id"), $$o.getField("o_w_id"), $$o.getField("o_entry_d"), 
$$o.getField("o_orderline")] project: [$$317, $$315, $$313, $$305, $$327] 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                                                
     -- ASSIGN  |PARTITIONED|
-                                                                               
       project ([$$o]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                                                               
       project ([$$o]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                                                                
       -- STREAM_PROJECT  |PARTITIONED|
-                                                                               
         exchange [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
2000000.0]
+                                                                               
         exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                                                                
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                               
           data-scan []<-[$$298, $$o] <- test.orders [cardinality: 1000000.0, 
op-cost: 1000000.0, total-cost: 1000000.0]
+                                                                               
           data-scan []<-[$$298, $$o] <- test.orders [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                                                
           -- DATASOURCE_SCAN  |PARTITIONED|
-                                                                               
             exchange
+                                                                               
             exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                                                                                
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                               
               empty-tuple-source
+                                                                               
               empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
                                                                                
               -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                                                  exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                                  exchange 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                                   -- 
HASH_PARTITION_EXCHANGE [$$333, $$334, $$332]  |PARTITIONED|
-                                                                    assign 
[$$311, $$334, $$333, $$332] <- 
[get-item(string-to-codepoint($$c.getField("c_state")), 0), 
$$c.getField("c_d_id"), $$c.getField("c_w_id"), $$c.getField("c_id")] project: 
[$$311, $$333, $$334, $$332] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                                                    assign 
[$$311, $$334, $$333, $$332] <- 
[get-item(string-to-codepoint($$c.getField("c_state")), 0), 
$$c.getField("c_d_id"), $$c.getField("c_w_id"), $$c.getField("c_id")] project: 
[$$311, $$333, $$334, $$332] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 
0.0, total-cost: 1000000.0]
                                                                     -- ASSIGN  
|PARTITIONED|
-                                                                      project 
([$$c]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                                      project 
([$$c]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                       -- 
STREAM_PROJECT  |PARTITIONED|
-                                                                        
exchange [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                                        
exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                         -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                          
data-scan []<-[$$300, $$c] <- test.customer [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 1000000.0]
+                                                                          
data-scan []<-[$$300, $$c] <- test.customer [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                                           -- 
DATASOURCE_SCAN  |PARTITIONED|
-                                                                            
exchange
+                                                                            
exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                                             -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                              
empty-tuple-source
+                                                                              
empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 
0.0]
                                                                               
-- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                                          exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                          exchange 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                           -- 
HASH_PARTITION_EXCHANGE [$$324]  |PARTITIONED|
-                                                            select 
(like($$i.getField("i_data"), "%b")) project: [$$324] [cardinality: 1000000.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                                                            select 
(and(lt($$324, 1000), like($$i.getField("i_data"), "%b"))) project: [$$324] 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                             -- STREAM_SELECT  
|PARTITIONED|
-                                                              assign [$$324] 
<- [$$i.getField("i_id")] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                                              assign [$$324] 
<- [$$i.getField("i_id")] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 
0.0, total-cost: 1000000.0]
                                                               -- ASSIGN  
|PARTITIONED|
-                                                                project 
([$$i]) [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                                project 
([$$i]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                                 -- 
STREAM_PROJECT  |PARTITIONED|
-                                                                  exchange 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 2000000.0]
+                                                                  exchange 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                                   -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                    data-scan 
[]<-[$$299, $$i] <- test.item [cardinality: 1000000.0, op-cost: 1000000.0, 
total-cost: 1000000.0]
+                                                                    data-scan 
[]<-[$$299, $$i] <- test.item [cardinality: 1000000.0, doc-size: -1.0, op-cost: 
0.0, total-cost: 1000000.0]
                                                                     -- 
DATASOURCE_SCAN  |PARTITIONED|
-                                                                      exchange
+                                                                      exchange 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                                       -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                        
empty-tuple-source
+                                                                        
empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 
0.0]
                                                                         -- 
EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                                  exchange [cardinality: 
1000000.0, op-cost: 4000000.0, total-cost: 5000000.0]
+                                                  exchange [cardinality: 
1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                   -- BROADCAST_EXCHANGE  
|PARTITIONED|
-                                                    assign [$$331, $$308] <- 
[$$n1.getField("n_nationkey"), $$n1.getField("n_regionkey")] project: [$$308, 
$$331] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                    assign [$$331, $$308] <- 
[$$n1.getField("n_nationkey"), $$n1.getField("n_regionkey")] project: [$$308, 
$$331] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                                     -- ASSIGN  |PARTITIONED|
-                                                      exchange [cardinality: 
1000000.0, op-cost: 4000000.0, total-cost: 5000000.0]
+                                                      exchange [cardinality: 
1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                       -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                        replicate 
[cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                        replicate 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                         -- REPLICATE  
|PARTITIONED|
-                                                          exchange 
[cardinality: 1000000.0, op-cost: 4000000.0, total-cost: 5000000.0]
+                                                          exchange 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                           -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                            project ([$$n1]) 
[cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                            project ([$$n1]) 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                             -- STREAM_PROJECT  
|PARTITIONED|
-                                                              exchange 
[cardinality: 1000000.0, op-cost: 4000000.0, total-cost: 5000000.0]
+                                                              exchange 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                               -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                data-scan 
[]<-[$$301, $$n1] <- test.nation [cardinality: 1000000.0, op-cost: 1000000.0, 
total-cost: 1000000.0]
+                                                                data-scan 
[]<-[$$301, $$n1] <- test.nation [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
                                                                 -- 
DATASOURCE_SCAN  |PARTITIONED|
-                                                                  exchange
+                                                                  exchange 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                                   -- 
ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                                    
empty-tuple-source
+                                                                    
empty-tuple-source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 
0.0]
                                                                     -- 
EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                                          exchange [cardinality: 1000000.0, 
op-cost: 4000000.0, total-cost: 5000000.0]
+                                          exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                           -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                            select (eq($$r.getField("r_name"), 
"Europe")) project: [$$309] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                            select (eq($$r.getField("r_name"), 
"Europe")) project: [$$309] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 
0.0, total-cost: 1000000.0]
                                             -- STREAM_SELECT  |PARTITIONED|
-                                              assign [$$309] <- 
[$$r.getField("r_regionkey")] [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                              assign [$$309] <- 
[$$r.getField("r_regionkey")] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 
0.0, total-cost: 1000000.0]
                                               -- ASSIGN  |PARTITIONED|
-                                                project ([$$r]) [cardinality: 
1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                project ([$$r]) [cardinality: 
1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                 -- STREAM_PROJECT  
|PARTITIONED|
-                                                  exchange [cardinality: 
1000000.0, op-cost: 4000000.0, total-cost: 5000000.0]
+                                                  exchange [cardinality: 
1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                                   -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                    data-scan []<-[$$302, $$r] 
<- test.region [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
1000000.0]
+                                                    data-scan []<-[$$302, $$r] 
<- test.region [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                                     -- DATASOURCE_SCAN  
|PARTITIONED|
-                                                      exchange
+                                                      exchange [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                       -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                        empty-tuple-source
+                                                        empty-tuple-source 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                         -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
-                                exchange [cardinality: 1000000.0, op-cost: 
4000000.0, total-cost: 5000000.0]
+                                exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
                                 -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                  assign [$$341, $$325] <- 
[$$su.getField("su_suppkey"), $$su.getField("su_nationkey")] project: [$$325, 
$$341] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  assign [$$341, $$325] <- 
[$$su.getField("su_suppkey"), $$su.getField("su_nationkey")] project: [$$325, 
$$341] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                   -- ASSIGN  |PARTITIONED|
-                                    project ([$$su]) [cardinality: 1000000.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                                    project ([$$su]) [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                     -- STREAM_PROJECT  |PARTITIONED|
-                                      exchange [cardinality: 1000000.0, 
op-cost: 4000000.0, total-cost: 5000000.0]
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        data-scan []<-[$$303, $$su] <- 
test.supplier [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
1000000.0]
+                                        data-scan []<-[$$303, $$su] <- 
test.supplier [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                                         -- DATASOURCE_SCAN  |PARTITIONED|
-                                          exchange
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                            empty-tuple-source
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                             -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
-                        exchange [cardinality: 1000000.0, op-cost: 4000000.0, 
total-cost: 5000000.0]
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
                         -- BROADCAST_EXCHANGE  |PARTITIONED|
-                          assign [$$342, $$326] <- [$$n2.getField("n_name"), 
$$n2.getField("n_nationkey")] project: [$$342, $$326] [cardinality: 1000000.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                          assign [$$342, $$326] <- [$$n2.getField("n_name"), 
$$n2.getField("n_nationkey")] project: [$$342, $$326] [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                           -- ASSIGN  |PARTITIONED|
-                            assign [$$n2] <- [$$n1] project: [$$n2] 
[cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            assign [$$n2] <- [$$n1] project: [$$n2] 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                             -- ASSIGN  |PARTITIONED|
-                              exchange [cardinality: 1000000.0, op-cost: 
4000000.0, total-cost: 5000000.0]
+                              exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                replicate [cardinality: 1000000.0, op-cost: 
0.0, total-cost: 1000000.0]
+                                replicate [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
                                 -- REPLICATE  |PARTITIONED|
-                                  exchange [cardinality: 1000000.0, op-cost: 
4000000.0, total-cost: 5000000.0]
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    project ([$$n1]) [cardinality: 1000000.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                                    project ([$$n1]) [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                     -- STREAM_PROJECT  |PARTITIONED|
-                                      exchange [cardinality: 1000000.0, 
op-cost: 4000000.0, total-cost: 5000000.0]
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        data-scan []<-[$$301, $$n1] <- 
test.nation [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                                        data-scan []<-[$$301, $$n1] <- 
test.nation [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
                                         -- DATASOURCE_SCAN  |PARTITIONED|
-                                          exchange
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                            empty-tuple-source
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                             -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/leftouterjoin/query-ASTERIXDB-2857.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/leftouterjoin/query-ASTERIXDB-2857.plan
index 11c1c970a9..a39f5ff171 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/leftouterjoin/query-ASTERIXDB-2857.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/leftouterjoin/query-ASTERIXDB-2857.plan
@@ -1,68 +1,68 @@
-distribute result [$$133] [cardinality: 5.0E11, op-cost: 0.0, total-cost: 
6000000.0]
+distribute result [$$133] [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 6000000.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 6000000.0]
+  exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, total-cost: 
6000000.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$133] <- [{"t0_unique1": $$145, "t1_unique1": $$146, 
"t2_unique1": $#3}] project: [$$133] [cardinality: 5.0E11, op-cost: 0.0, 
total-cost: 6000000.0]
+    assign [$$133] <- [{"t0_unique1": $$145, "t1_unique1": $$146, 
"t2_unique1": $#3}] project: [$$133] [cardinality: 5.0E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 6000000.0]
     -- ASSIGN  |PARTITIONED|
-      exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 6000000.0]
+      exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, total-cost: 
6000000.0]
       -- SORT_MERGE_EXCHANGE [$$145(ASC), $$146(ASC), $#3(ASC) ]  |PARTITIONED|
-        order (ASC, $$145) (ASC, $$146) (ASC, $#3) [cardinality: 5.0E11, 
op-cost: 0.0, total-cost: 6000000.0]
+        order (ASC, $$145) (ASC, $$146) (ASC, $#3) [cardinality: 5.0E11, 
doc-size: -2.0, op-cost: 0.0, total-cost: 6000000.0]
         -- STABLE_SORT [$$145(ASC), $$146(ASC), $#3(ASC)]  |PARTITIONED|
-          exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 6000000.0]
+          exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 6000000.0]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-            project ([$$145, $$146, $#3]) [cardinality: 5.0E11, op-cost: 0.0, 
total-cost: 6000000.0]
+            project ([$$145, $$146, $#3]) [cardinality: 5.0E11, doc-size: 
-2.0, op-cost: 0.0, total-cost: 6000000.0]
             -- STREAM_PROJECT  |PARTITIONED|
-              exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 
6000000.0]
+              exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 6000000.0]
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                left outer join (eq(numeric-add($$136, $$138), $$159)) 
[cardinality: 9.223372036854776E16, op-cost: 5.00004E11, total-cost: 5.00015E11]
+                left outer join (eq(numeric-add($$136, $$138), $$159)) 
[cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 5.00004E11, 
total-cost: 5.00015E11]
                 -- NESTED_LOOP  |PARTITIONED|
-                  exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 
6000000.0]
+                  exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 6000000.0]
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    assign [$$159] <- [numeric-multiply(2, $$137)] project: 
[$$145, $$146, $$136, $$159] [cardinality: 5.0E11, op-cost: 0.0, total-cost: 
6000000.0]
+                    assign [$$159] <- [numeric-multiply(2, $$137)] project: 
[$$145, $$146, $$136, $$159] [cardinality: 5.0E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 6000000.0]
                     -- ASSIGN  |PARTITIONED|
-                      exchange [cardinality: 5.0E11, op-cost: 0.0, total-cost: 
6000000.0]
+                      exchange [cardinality: 5.0E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 6000000.0]
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        join (eq($$136, $$137)) [cardinality: 5.0E11, op-cost: 
2000000.0, total-cost: 6000000.0]
+                        join (eq($$136, $$137)) [cardinality: 5.0E11, 
doc-size: -2.0, op-cost: 2000000.0, total-cost: 6000000.0]
                         -- HYBRID_HASH_JOIN [$$136][$$137]  |PARTITIONED|
-                          exchange [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 2000000.0]
+                          exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
                           -- HASH_PARTITION_EXCHANGE [$$136]  |PARTITIONED|
-                            assign [$$145] <- [$$tenk.getField(0)] project: 
[$$145, $$136] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            assign [$$145] <- [$$tenk.getField(0)] project: 
[$$145, $$136] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                             -- ASSIGN  |PARTITIONED|
-                              exchange [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 2000000.0]
-                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                unnest-map [$$136, $$tenk] <- 
index-search("tenk", 0, "Default", "test", "tenk", false, false, 0, 1, $$160, 
true, false, false) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
1000000.0]
-                                -- BTREE_SEARCH  |PARTITIONED|
-                                  exchange
-                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    assign [$$160] <- [2]
-                                    -- ASSIGN  |PARTITIONED|
-                                      empty-tuple-source
+                              select (and(lt($$136, 4), lt($$136, 2))) 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- STREAM_SELECT  |PARTITIONED|
+                                exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  data-scan []<-[$$136, $$tenk] <- test.tenk 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- DATASOURCE_SCAN  |PARTITIONED|
+                                    exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                       -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                          exchange [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 2000000.0]
+                          exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
                           -- HASH_PARTITION_EXCHANGE [$$137]  |PARTITIONED|
-                            assign [$$146] <- [$$tenk.getField(0)] project: 
[$$146, $$137] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
+                            assign [$$146] <- [$$tenk.getField(0)] project: 
[$$146, $$137] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
                             -- ASSIGN  |PARTITIONED|
-                              exchange [cardinality: 1000000.0, op-cost: 
1000000.0, total-cost: 2000000.0]
-                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                unnest-map [$$137, $$tenk] <- 
index-search("tenk", 0, "Default", "test", "tenk", false, false, 0, 1, $$163, 
true, false, false) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
1000000.0]
-                                -- BTREE_SEARCH  |PARTITIONED|
-                                  exchange
-                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    assign [$$163] <- [4]
-                                    -- ASSIGN  |PARTITIONED|
-                                      empty-tuple-source
+                              select (and(lt($$137, 2), lt($$137, 4))) 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- STREAM_SELECT  |PARTITIONED|
+                                exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  data-scan []<-[$$137, $$tenk] <- test.tenk 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- DATASOURCE_SCAN  |PARTITIONED|
+                                    exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                       -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                  exchange
+                  exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                   -- BROADCAST_EXCHANGE  |PARTITIONED|
-                    assign [$#3] <- [{"unique1": $$tenk.getField(0), 
"unique2": $$138}.getField(0)] project: [$#3, $$138]
+                    assign [$#3] <- [{"unique1": $$tenk.getField(0), 
"unique2": $$138}.getField(0)] project: [$#3, $$138] [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ASSIGN  |PARTITIONED|
-                      exchange
+                      exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        unnest-map [$$138, $$tenk] <- index-search("tenk", 0, 
"Default", "test", "tenk", false, false, 0, 1, $$166, true, false, false) 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                        unnest-map [$$138, $$tenk] <- index-search("tenk", 0, 
"Default", "test", "tenk", false, false, 0, 1, $$160, true, false, false) 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 1000000.0, total-cost: 
1000000.0]
                         -- BTREE_SEARCH  |PARTITIONED|
-                          exchange
+                          exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            assign [$$166] <- [6]
+                            assign [$$160] <- [6] [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
                             -- ASSIGN  |PARTITIONED|
-                              empty-tuple-source
+                              empty-tuple-source [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
                               -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_01_ps.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_01_ps.plan
index e592d71465..01c150a9f0 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_01_ps.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_01_ps.plan
@@ -1,78 +1,90 @@
-distribute result [$$35] [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+distribute result [$$35] [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+  exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 
1.000006E12]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 1.000006E12]
     -- ASSIGN  |PARTITIONED|
-      project ([$$38, $$39]) [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+      project ([$$38, $$39]) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
       -- STREAM_PROJECT  |PARTITIONED|
-        exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+        exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
           -- STABLE_SORT [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-            exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+            exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
             -- RANGE_PARTITION_EXCHANGE [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-              forward: shared-variable = $$51 [cardinality: 2.5E11, op-cost: 
0.0, total-cost: 2.50009E11]
+              forward: shared-variable = $$49 [cardinality: 2.5E11, doc-size: 
-2.0, op-cost: 0.0, total-cost: 1.000006E12]
               -- FORWARD  |PARTITIONED|
-                exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  replicate [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                  replicate [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                   -- REPLICATE  |PARTITIONED|
-                    exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                    exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      select (contains($$38, $$39)) [cardinality: 2.5E11, 
op-cost: 2.50004E11, total-cost: 2.50009E11]
-                      -- STREAM_SELECT  |PARTITIONED|
-                        assign [$$39] <- [$$o2.getField(2)] project: [$$40, 
$$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
-                        -- ASSIGN  |PARTITIONED|
-                          exchange [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1000000.0]
-                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            unnest-map [$$41, $$o2] <- index-search("CSX", 0, 
"Default", "test", "CSX", true, true, 1, $$40, 0, false, true, false) 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                            -- BTREE_SEARCH  |PARTITIONED|
-                              exchange
-                              -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                assign [$$38] <- [$$o1.getField("title")] 
project: [$$40, $$38]
-                                -- ASSIGN  |PARTITIONED|
-                                  exchange
-                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    data-scan []<-[$$40, $$o1] <- test.DBLP 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                    -- DATASOURCE_SCAN  |PARTITIONED|
-                                      exchange
-                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        empty-tuple-source
-                                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                exchange
+                      join (and(contains($$38, $$39), lt($$40, $$41))) 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 1.000006E12]
+                      -- NESTED_LOOP  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          assign [$$38] <- [$$o1.getField("title")] project: 
[$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$40, $$o1] <- test.DBLP 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- BROADCAST_EXCHANGE  |PARTITIONED|
+                          assign [$$39] <- [$$o2.getField(2)] project: [$$39, 
$$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$41, $$o2] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                 -- BROADCAST_EXCHANGE  |PARTITIONED|
-                  aggregate [$$51] <- [agg-range-map($$48, $$49, $$50)]
+                  aggregate [$$49] <- [agg-range-map($$46, $$47, $$48)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                   -- AGGREGATE  |UNPARTITIONED|
-                    exchange
+                    exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                     -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
-                      aggregate [$$48, $$49, $$50] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)]
+                      aggregate [$$46, $$47, $$48] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |PARTITIONED|
-                        project ([$$40, $$41])
+                        project ([$$40, $$41]) [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange
+                          exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            replicate [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                            replicate [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                             -- REPLICATE  |PARTITIONED|
-                              exchange [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                              exchange [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                select (contains($$38, $$39)) [cardinality: 
2.5E11, op-cost: 2.50004E11, total-cost: 2.50009E11]
-                                -- STREAM_SELECT  |PARTITIONED|
-                                  assign [$$39] <- [$$o2.getField(2)] project: 
[$$40, $$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
-                                  -- ASSIGN  |PARTITIONED|
-                                    exchange [cardinality: 1000000.0, op-cost: 
0.0, total-cost: 1000000.0]
-                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                      unnest-map [$$41, $$o2] <- 
index-search("CSX", 0, "Default", "test", "CSX", true, true, 1, $$40, 0, false, 
true, false) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                      -- BTREE_SEARCH  |PARTITIONED|
-                                        exchange
-                                        -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                          assign [$$38] <- 
[$$o1.getField("title")] project: [$$40, $$38]
-                                          -- ASSIGN  |PARTITIONED|
-                                            exchange
-                                            -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                              data-scan []<-[$$40, $$o1] <- 
test.DBLP [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                              -- DATASOURCE_SCAN  |PARTITIONED|
-                                                exchange
-                                                -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                  empty-tuple-source
-                                                  -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                join (and(contains($$38, $$39), lt($$40, 
$$41))) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 
1.000006E12]
+                                -- NESTED_LOOP  |PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    assign [$$38] <- [$$o1.getField("title")] 
project: [$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$40, $$o1] <- 
test.DBLP [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- BROADCAST_EXCHANGE  |PARTITIONED|
+                                    assign [$$39] <- [$$o2.getField(2)] 
project: [$$39, $$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$41, $$o2] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_02_ps.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_02_ps.plan
index 63e9cd35a0..5fdfd40609 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_02_ps.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/nested-open-index/inverted-index-join/ngram-contains_02_ps.plan
@@ -1,78 +1,90 @@
-distribute result [$$35] [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+distribute result [$$35] [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+  exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 
1.000006E12]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 1.000006E12]
     -- ASSIGN  |PARTITIONED|
-      project ([$$38, $$39]) [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+      project ([$$38, $$39]) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
       -- STREAM_PROJECT  |PARTITIONED|
-        exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+        exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
           -- STABLE_SORT [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-            exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+            exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
             -- RANGE_PARTITION_EXCHANGE [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-              forward: shared-variable = $$51 [cardinality: 2.5E11, op-cost: 
0.0, total-cost: 2.50009E11]
+              forward: shared-variable = $$49 [cardinality: 2.5E11, doc-size: 
-2.0, op-cost: 0.0, total-cost: 1.000006E12]
               -- FORWARD  |PARTITIONED|
-                exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  replicate [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                  replicate [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                   -- REPLICATE  |PARTITIONED|
-                    exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                    exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      select (contains($$38, $$39)) [cardinality: 2.5E11, 
op-cost: 2.50004E11, total-cost: 2.50009E11]
-                      -- STREAM_SELECT  |PARTITIONED|
-                        assign [$$39] <- [$$o2.getField(2)] project: [$$40, 
$$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
-                        -- ASSIGN  |PARTITIONED|
-                          exchange [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1000000.0]
-                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            unnest-map [$$41, $$o2] <- index-search("DBLP", 0, 
"Default", "test", "DBLP", true, true, 1, $$40, 0, false, true, false) 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                            -- BTREE_SEARCH  |PARTITIONED|
-                              exchange
-                              -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                assign [$$38] <- [$$o1.getField("title")] 
project: [$$40, $$38]
-                                -- ASSIGN  |PARTITIONED|
-                                  exchange
-                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    data-scan []<-[$$40, $$o1] <- test.CSX 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                    -- DATASOURCE_SCAN  |PARTITIONED|
-                                      exchange
-                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        empty-tuple-source
-                                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                exchange
+                      join (and(contains($$38, $$39), lt($$40, $$41))) 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 1.000006E12]
+                      -- NESTED_LOOP  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          assign [$$38] <- [$$o1.getField("title")] project: 
[$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$40, $$o1] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- BROADCAST_EXCHANGE  |PARTITIONED|
+                          assign [$$39] <- [$$o2.getField(2)] project: [$$39, 
$$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$41, $$o2] <- test.DBLP 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                 -- BROADCAST_EXCHANGE  |PARTITIONED|
-                  aggregate [$$51] <- [agg-range-map($$48, $$49, $$50)]
+                  aggregate [$$49] <- [agg-range-map($$46, $$47, $$48)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                   -- AGGREGATE  |UNPARTITIONED|
-                    exchange
+                    exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                     -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
-                      aggregate [$$48, $$49, $$50] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)]
+                      aggregate [$$46, $$47, $$48] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |PARTITIONED|
-                        project ([$$40, $$41])
+                        project ([$$40, $$41]) [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange
+                          exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            replicate [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                            replicate [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                             -- REPLICATE  |PARTITIONED|
-                              exchange [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                              exchange [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                select (contains($$38, $$39)) [cardinality: 
2.5E11, op-cost: 2.50004E11, total-cost: 2.50009E11]
-                                -- STREAM_SELECT  |PARTITIONED|
-                                  assign [$$39] <- [$$o2.getField(2)] project: 
[$$40, $$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
-                                  -- ASSIGN  |PARTITIONED|
-                                    exchange [cardinality: 1000000.0, op-cost: 
0.0, total-cost: 1000000.0]
-                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                      unnest-map [$$41, $$o2] <- 
index-search("DBLP", 0, "Default", "test", "DBLP", true, true, 1, $$40, 0, 
false, true, false) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 
1000000.0]
-                                      -- BTREE_SEARCH  |PARTITIONED|
-                                        exchange
-                                        -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                          assign [$$38] <- 
[$$o1.getField("title")] project: [$$40, $$38]
-                                          -- ASSIGN  |PARTITIONED|
-                                            exchange
-                                            -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                              data-scan []<-[$$40, $$o1] <- 
test.CSX [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                              -- DATASOURCE_SCAN  |PARTITIONED|
-                                                exchange
-                                                -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                  empty-tuple-source
-                                                  -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                join (and(contains($$38, $$39), lt($$40, 
$$41))) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 
1.000006E12]
+                                -- NESTED_LOOP  |PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    assign [$$38] <- [$$o1.getField("title")] 
project: [$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$40, $$o1] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- BROADCAST_EXCHANGE  |PARTITIONED|
+                                    assign [$$39] <- [$$o2.getField(2)] 
project: [$$39, $$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$41, $$o2] <- 
test.DBLP [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/open-index-enforced/inverted-index-join/ngram-contains_01_ps.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/open-index-enforced/inverted-index-join/ngram-contains_01_ps.plan
index e592d71465..01c150a9f0 100644
--- 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/open-index-enforced/inverted-index-join/ngram-contains_01_ps.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/open-index-enforced/inverted-index-join/ngram-contains_01_ps.plan
@@ -1,78 +1,90 @@
-distribute result [$$35] [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+distribute result [$$35] [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+  exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 
1.000006E12]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+    assign [$$35] <- [{"title1": $$38, "title2": $$39}] project: [$$35] 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, total-cost: 1.000006E12]
     -- ASSIGN  |PARTITIONED|
-      project ([$$38, $$39]) [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+      project ([$$38, $$39]) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
       -- STREAM_PROJECT  |PARTITIONED|
-        exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 2.50009E11]
+        exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+          order (ASC, $$40) (ASC, $$41) [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
           -- STABLE_SORT [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-            exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+            exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
             -- RANGE_PARTITION_EXCHANGE [$$40(ASC), $$41(ASC)]  |PARTITIONED|
-              forward: shared-variable = $$51 [cardinality: 2.5E11, op-cost: 
0.0, total-cost: 2.50009E11]
+              forward: shared-variable = $$49 [cardinality: 2.5E11, doc-size: 
-2.0, op-cost: 0.0, total-cost: 1.000006E12]
               -- FORWARD  |PARTITIONED|
-                exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 0.0, 
total-cost: 1.000006E12]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  replicate [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                  replicate [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                   -- REPLICATE  |PARTITIONED|
-                    exchange [cardinality: 2.5E11, op-cost: 0.0, total-cost: 
2.50009E11]
+                    exchange [cardinality: 2.5E11, doc-size: -2.0, op-cost: 
0.0, total-cost: 1.000006E12]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      select (contains($$38, $$39)) [cardinality: 2.5E11, 
op-cost: 2.50004E11, total-cost: 2.50009E11]
-                      -- STREAM_SELECT  |PARTITIONED|
-                        assign [$$39] <- [$$o2.getField(2)] project: [$$40, 
$$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 1000000.0]
-                        -- ASSIGN  |PARTITIONED|
-                          exchange [cardinality: 1000000.0, op-cost: 0.0, 
total-cost: 1000000.0]
-                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            unnest-map [$$41, $$o2] <- index-search("CSX", 0, 
"Default", "test", "CSX", true, true, 1, $$40, 0, false, true, false) 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                            -- BTREE_SEARCH  |PARTITIONED|
-                              exchange
-                              -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                assign [$$38] <- [$$o1.getField("title")] 
project: [$$40, $$38]
-                                -- ASSIGN  |PARTITIONED|
-                                  exchange
-                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    data-scan []<-[$$40, $$o1] <- test.DBLP 
[cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                    -- DATASOURCE_SCAN  |PARTITIONED|
-                                      exchange
-                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        empty-tuple-source
-                                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                exchange
+                      join (and(contains($$38, $$39), lt($$40, $$41))) 
[cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 1.000006E12]
+                      -- NESTED_LOOP  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          assign [$$38] <- [$$o1.getField("title")] project: 
[$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$40, $$o1] <- test.DBLP 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                        exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                        -- BROADCAST_EXCHANGE  |PARTITIONED|
+                          assign [$$39] <- [$$o2.getField(2)] project: [$$39, 
$$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                          -- ASSIGN  |PARTITIONED|
+                            exchange [cardinality: 1000000.0, doc-size: -1.0, 
op-cost: 0.0, total-cost: 1000000.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              data-scan []<-[$$41, $$o2] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                 -- BROADCAST_EXCHANGE  |PARTITIONED|
-                  aggregate [$$51] <- [agg-range-map($$48, $$49, $$50)]
+                  aggregate [$$49] <- [agg-range-map($$46, $$47, $$48)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                   -- AGGREGATE  |UNPARTITIONED|
-                    exchange
+                    exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
                     -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
-                      aggregate [$$48, $$49, $$50] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)]
+                      aggregate [$$46, $$47, $$48] <- 
[agg-local-sampling($$40, $$41), agg-null-writer($$40), agg-null-writer($$41)] 
[cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |PARTITIONED|
-                        project ([$$40, $$41])
+                        project ([$$40, $$41]) [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange
+                          exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            replicate [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                            replicate [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                             -- REPLICATE  |PARTITIONED|
-                              exchange [cardinality: 2.5E11, op-cost: 0.0, 
total-cost: 2.50009E11]
+                              exchange [cardinality: 2.5E11, doc-size: -2.0, 
op-cost: 0.0, total-cost: 1.000006E12]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                select (contains($$38, $$39)) [cardinality: 
2.5E11, op-cost: 2.50004E11, total-cost: 2.50009E11]
-                                -- STREAM_SELECT  |PARTITIONED|
-                                  assign [$$39] <- [$$o2.getField(2)] project: 
[$$40, $$38, $$41, $$39] [cardinality: 1000000.0, op-cost: 0.0, total-cost: 
1000000.0]
-                                  -- ASSIGN  |PARTITIONED|
-                                    exchange [cardinality: 1000000.0, op-cost: 
0.0, total-cost: 1000000.0]
-                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                      unnest-map [$$41, $$o2] <- 
index-search("CSX", 0, "Default", "test", "CSX", true, true, 1, $$40, 0, false, 
true, false) [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                      -- BTREE_SEARCH  |PARTITIONED|
-                                        exchange
-                                        -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                          assign [$$38] <- 
[$$o1.getField("title")] project: [$$40, $$38]
-                                          -- ASSIGN  |PARTITIONED|
-                                            exchange
-                                            -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                              data-scan []<-[$$40, $$o1] <- 
test.DBLP [cardinality: 1000000.0, op-cost: 1000000.0, total-cost: 1000000.0]
-                                              -- DATASOURCE_SCAN  |PARTITIONED|
-                                                exchange
-                                                -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
-                                                  empty-tuple-source
-                                                  -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                join (and(contains($$38, $$39), lt($$40, 
$$41))) [cardinality: 2.5E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 
1.000006E12]
+                                -- NESTED_LOOP  |PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    assign [$$38] <- [$$o1.getField("title")] 
project: [$$38, $$40] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$40, $$o1] <- 
test.DBLP [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 
1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
+                                  exchange [cardinality: 1000000.0, doc-size: 
-1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                  -- BROADCAST_EXCHANGE  |PARTITIONED|
+                                    assign [$$39] <- [$$o2.getField(2)] 
project: [$$39, $$41] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, 
total-cost: 1000000.0]
+                                    -- ASSIGN  |PARTITIONED|
+                                      exchange [cardinality: 1000000.0, 
doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                        data-scan []<-[$$41, $$o2] <- test.CSX 
[cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                        -- DATASOURCE_SCAN  |PARTITIONED|
+                                          exchange [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                            empty-tuple-source [cardinality: 
0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.06.plan
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.06.plan
index 2b6dce7feb..4349cae6f4 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.06.plan
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.06.plan
@@ -1,34 +1,46 @@
-distribute result [$$36] [cardinality: 601.63, doc-size: 10.0, op-cost: 0.0, 
total-cost: 19667.04]
+distribute result [$$36] [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, 
total-cost: 98061.73]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 601.63, doc-size: 10.0, op-cost: 0.0, total-cost: 
19667.04]
+  exchange [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, total-cost: 
98061.73]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$36] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": 
$$42}] project: [$$36] [cardinality: 601.63, doc-size: 10.0, op-cost: 0.0, 
total-cost: 19667.04]
+    assign [$$36] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": 
$$42}] project: [$$36] [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, 
total-cost: 98061.73]
     -- ASSIGN  |PARTITIONED|
-      exchange [cardinality: 601.63, doc-size: 10.0, op-cost: 0.0, total-cost: 
19667.04]
+      exchange [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, total-cost: 
98061.73]
       -- SORT_MERGE_EXCHANGE [$$43(ASC), $$44(ASC), $$42(ASC) ]  |PARTITIONED|
-        order (ASC, $$43) (ASC, $$44) (ASC, $$42) [cardinality: 601.63, 
doc-size: 10.0, op-cost: 0.0, total-cost: 19667.04]
+        order (ASC, $$43) (ASC, $$44) (ASC, $$42) [cardinality: 6016.3, 
doc-size: 15.0, op-cost: 0.0, total-cost: 98061.73]
         -- STABLE_SORT [$$43(ASC), $$44(ASC), $$42(ASC)]  |PARTITIONED|
-          exchange [cardinality: 601.63, doc-size: 10.0, op-cost: 0.0, 
total-cost: 14112.35]
+          exchange [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, 
total-cost: 22529.12]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-            select (eq($$43, $$42)) [cardinality: 601.63, doc-size: 10.0, 
op-cost: 0.0, total-cost: 14112.35]
-            -- STREAM_SELECT  |PARTITIONED|
-              assign [$$42] <- [$$l.getField(2)] project: [$$43, $$44, $$42] 
[cardinality: 6010.65, doc-size: 10.0, op-cost: 0.0, total-cost: 6005.0]
-              -- ASSIGN  |PARTITIONED|
-                project ([$$43, $$44, $$l]) [cardinality: 6010.65, doc-size: 
10.0, op-cost: 0.0, total-cost: 6005.0]
-                -- STREAM_PROJECT  |PARTITIONED|
-                  exchange [cardinality: 6010.65, doc-size: 10.0, op-cost: 
0.0, total-cost: 6005.0]
-                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    unnest-map [$$44, $$45, $$l] <- index-search("LineItem", 
0, "Default", "tpch", "LineItem", true, true, 1, $$43, 1, $$43, true, true, 
true) [cardinality: 6010.65, doc-size: 10.0, op-cost: 0.0, total-cost: 6005.0]
-                    -- BTREE_SEARCH  |PARTITIONED|
-                      exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, 
total-cost: 0.0]
-                      -- BROADCAST_EXCHANGE  |PARTITIONED|
-                        project ([$$43]) [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
-                        -- STREAM_PROJECT  |PARTITIONED|
-                          exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 
0.0, total-cost: 0.0]
-                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            data-scan []<-[$$43, $$o] <- tpch.Orders 
[cardinality: 1500.0, doc-size: 5.0, op-cost: 1500.0, total-cost: 1500.0]
-                            -- DATASOURCE_SCAN  |PARTITIONED|
-                              exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
-                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                empty-tuple-source [cardinality: 0.0, 
doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+            project ([$$43, $$44, $$42]) [cardinality: 6016.3, doc-size: 15.0, 
op-cost: 0.0, total-cost: 22529.12]
+            -- STREAM_PROJECT  |PARTITIONED|
+              exchange [cardinality: 6016.3, doc-size: 15.0, op-cost: 0.0, 
total-cost: 22529.12]
+              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                join (and(eq($$43, $$44), eq($$49, $$42))) [cardinality: 
6016.3, doc-size: 15.0, op-cost: 7512.06, total-cost: 22529.12]
+                -- HYBRID_HASH_JOIN [$$44, $$42][$$43, $$49]  |PARTITIONED|
+                  exchange [cardinality: 6005.0, doc-size: 10.0, op-cost: 0.0, 
total-cost: 6005.0]
+                  -- HASH_PARTITION_EXCHANGE [$$44, $$42]  |PARTITIONED|
+                    assign [$$42] <- [$$l.getField(2)] project: [$$44, $$42] 
[cardinality: 6005.0, doc-size: 10.0, op-cost: 0.0, total-cost: 6005.0]
+                    -- ASSIGN  |PARTITIONED|
+                      project ([$$44, $$l]) [cardinality: 6005.0, doc-size: 
10.0, op-cost: 0.0, total-cost: 6005.0]
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        exchange [cardinality: 6005.0, doc-size: 10.0, 
op-cost: 0.0, total-cost: 6005.0]
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          data-scan []<-[$$44, $$45, $$l] <- tpch.LineItem 
[cardinality: 6005.0, doc-size: 10.0, op-cost: 0.0, total-cost: 6005.0]
+                          -- DATASOURCE_SCAN  |PARTITIONED|
+                            exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              empty-tuple-source [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                  exchange [cardinality: 1500.0, doc-size: 5.0, op-cost: 0.0, 
total-cost: 1500.0]
+                  -- HASH_PARTITION_EXCHANGE [$$43, $$49]  |PARTITIONED|
+                    assign [$$49] <- [$$43] [cardinality: 1500.0, doc-size: 
5.0, op-cost: 0.0, total-cost: 1500.0]
+                    -- ASSIGN  |PARTITIONED|
+                      project ([$$43]) [cardinality: 1500.0, doc-size: 5.0, 
op-cost: 0.0, total-cost: 1500.0]
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        exchange [cardinality: 1500.0, doc-size: 5.0, op-cost: 
0.0, total-cost: 1500.0]
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          data-scan []<-[$$43, $$o] <- tpch.Orders 
[cardinality: 1500.0, doc-size: 5.0, op-cost: 0.0, total-cost: 1500.0]
+                          -- DATASOURCE_SCAN  |PARTITIONED|
+                            exchange [cardinality: 0.0, doc-size: 0.0, 
op-cost: 0.0, total-cost: 0.0]
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              empty-tuple-source [cardinality: 0.0, doc-size: 
0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|

Reply via email to