You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by vs...@apache.org on 2023/11/17 15:10:06 UTC

(asterixdb) branch master updated: [ASTERIXDB-3303][COMP] Projection Sizes continued

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

vsarathy1 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 9104333009 [ASTERIXDB-3303][COMP] Projection Sizes continued
9104333009 is described below

commit 910433300941d09591a84a07057f8d72678131a0
Author: murali4104 <mu...@couchbase.com>
AuthorDate: Thu Nov 16 11:58:18 2023 -0800

    [ASTERIXDB-3303][COMP] Projection Sizes continued
    
    Change-Id: I543da55af0c71961c84dfcafd8257f6e5e608cf9
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17953
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Tested-by: Vijay Sarathy <vi...@couchbase.com>
    Reviewed-by: Vijay Sarathy <vi...@couchbase.com>
---
 .../asterix/optimizer/rules/cbo/JoinEnum.java      | 101 +++++++++++++--------
 .../apache/asterix/optimizer/rules/cbo/Stats.java  |   7 ++
 .../join-queries/join-queries.3.plan               |  20 ++--
 .../join-queries/join-queries.4.plan               |  22 ++---
 .../join-queries/join-queries.5.plan               |  34 +++----
 .../join-queries/join-queries.6.plan               |  30 +++---
 .../join-queries/join-queries.7.plan               |  30 +++---
 .../join-queries/join-queries.8.plan               |  38 ++++----
 .../hash-join-with-redundant-variable.06.plan      |  28 +++---
 .../hash-join-with-redundant-variable.08.plan      |  14 +--
 .../results_cbo/query_index/q01/q01.024.plan       |  16 ++--
 .../results_cbo/query_index/q01/q01.025.plan       |  16 ++--
 .../results_cbo/query_index/q01/q01.026.plan       |  60 ++++++------
 .../results_cbo/query_index/q01/q01.027.plan       |  18 ++--
 .../results_cbo/query_index/q01/q01.028.plan       |  60 ++++++------
 .../results_cbo/query_index/q01/q01.029.plan       |  60 ++++++------
 .../results_cbo/query_index/q01/q01.030.plan       |  60 ++++++------
 .../results_cbo/query_index/q01/q01.031.plan       |  60 ++++++------
 18 files changed, 341 insertions(+), 333 deletions(-)

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 244279dd2c..3a5dda7883 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
@@ -39,7 +39,6 @@ import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.declared.SampleDataSource;
 import org.apache.asterix.metadata.entities.Index;
 import org.apache.asterix.om.base.AOrderedList;
-import org.apache.asterix.om.base.ARecord;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.constants.AsterixConstantValue;
 import org.apache.asterix.om.functions.BuiltinFunctions;
@@ -78,8 +77,10 @@ import org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperato
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
 import org.apache.hyracks.algebricks.core.algebra.prettyprint.IPlanPrettyPrinter;
 import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
 import org.apache.hyracks.algebricks.core.rewriter.base.PhysicalOptimizationConfig;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.api.exceptions.Warning;
@@ -866,7 +867,6 @@ public class JoinEnum {
                 }
                 double origDatasetCard, finalDatasetCard, sampleCard;
 
-                ILogicalOperator parent = findDataSourceScanOperatorParent(leafInput);
                 DataSourceScanOperator scanOp = findDataSourceScanOperator(leafInput);
                 if (scanOp == null) {
                     continue; // what happens to the cards and sizes then? this may happen in case of in lists
@@ -885,51 +885,72 @@ public class JoinEnum {
 
                 List<List<IAObject>> result;
                 SelectOperator selop = (SelectOperator) findASelectOp(leafInput);
+                if (selop == null) { // add a SelectOperator with TRUE condition. The code below becomes simpler with a select operator.
+                    selop = new SelectOperator(new MutableObject<>(ConstantExpression.TRUE));
+                    ILogicalOperator op = selop;
+                    op.getInputs().add(new MutableObject<>(leafInput));
+                    leafInput = op;
+                }
+                ILogicalOperator parent = findDataSourceScanOperatorParent(leafInput);
+                Mutable<ILogicalOperator> ref = new MutableObject<>(leafInput);
 
-                if (jn.getCardinality() == jn.getOrigCardinality() && selop != null) { // this means there was no selectivity hint provided
-                    SampleDataSource sampledatasource = getSampleDataSource(scanOp);
-                    DataSourceScanOperator deepCopyofScan =
-                            (DataSourceScanOperator) OperatorManipulationUtil.bottomUpCopyOperators(scanOp);
-                    deepCopyofScan.setDataSource(sampledatasource);
-
-                    // if there is only one conjunct, I do not have to call the sampling query during index selection!
-                    // insert this in place of the scandatasourceOp.
-                    parent.getInputs().get(0).setValue(deepCopyofScan);
-                    // There are predicates here. So skip the predicates and get the original dataset card.
-                    // Now apply all the predicates and get the card after all predicates are applied.
-                    result = stats.runSamplingQuery(this.optCtx, leafInput);
-                    double predicateCardinality = stats.findPredicateCardinality(result);
+                OperatorPropertiesUtil.typeOpRec(ref, optCtx);
+                if (LOGGER.isTraceEnabled()) {
+                    String viewPlan = new ALogicalPlanImpl(ref).toString(); //useful when debugging
+                    LOGGER.trace("viewPlan");
+                    LOGGER.trace(viewPlan);
+                }
 
-                    double projectedSize = -1.0;
-                    if (predicateCardinality > 0.0) { // otherwise, we get nulls for the averages
+                SampleDataSource sampledatasource = getSampleDataSource(scanOp);
+                DataSourceScanOperator deepCopyofScan =
+                        (DataSourceScanOperator) OperatorManipulationUtil.bottomUpCopyOperators(scanOp);
+                deepCopyofScan.setDataSource(sampledatasource);
+
+                // if there is only one conjunct, I do not have to call the sampling query during index selection!
+                // insert this in place of the scandatasourceOp.
+                parent.getInputs().get(0).setValue(deepCopyofScan);
+                // There are predicates here. So skip the predicates and get the original dataset card.
+                // Now apply all the predicates and get the card after all predicates are applied.
+                result = stats.runSamplingQuery(this.optCtx, leafInput);
+                double predicateCardinality = stats.findPredicateCardinality(result);
+
+                double projectedSize;
+                if (predicateCardinality > 0.0) { // otherwise, we get nulls for the averages
+                    projectedSize = stats.findProjectedSize(result);
+                } else { // in case we did not get any tuples from the sample, get the size by setting the predicate to true.
+                    ILogicalExpression saveExpr = selop.getCondition().getValue();
+                    selop.getCondition().setValue(ConstantExpression.TRUE);
+                    result = stats.runSamplingQuery(this.optCtx, leafInput);
+                    double x = stats.findPredicateCardinality(result);
+                    // better to check if x is 0
+                    if (x == 0.0) {
+                        int fields = stats.numberOfFields(result);
+                        projectedSize = fields * 100; // cant think of anything better... cards are more important anyway
+                    } else {
                         projectedSize = stats.findProjectedSize(result);
                     }
-                    if (predicateCardinality == 0.0) {
-                        predicateCardinality = 0.0001 * idxDetails.getSampleCardinalityTarget();
-                    }
-                    // now scale up
-                    sampleCard = Math.min(idxDetails.getSampleCardinalityTarget(), origDatasetCard);
-                    if (sampleCard == 0) { // should not happen unless the original dataset is empty
-                        sampleCard = 1; // we may have to make some adjustments to costs when the sample returns very rows.
-
-                        IWarningCollector warningCollector = optCtx.getWarningCollector();
-                        if (warningCollector.shouldWarn()) {
-                            warningCollector
-                                    .warn(Warning.of(scanOp.getSourceLocation(), ErrorCode.SAMPLE_HAS_ZERO_ROWS));
-                        }
+                    selop.getCondition().setValue(saveExpr); // restore the expression
+                }
+                if (predicateCardinality == 0.0) {
+                    predicateCardinality = 0.0001 * idxDetails.getSampleCardinalityTarget();
+                }
+                // now scale up
+                sampleCard = Math.min(idxDetails.getSampleCardinalityTarget(), origDatasetCard);
+                if (sampleCard == 0) { // should not happen unless the original dataset is empty
+                    sampleCard = 1; // we may have to make some adjustments to costs when the sample returns very rows.
+
+                    IWarningCollector warningCollector = optCtx.getWarningCollector();
+                    if (warningCollector.shouldWarn()) {
+                        warningCollector.warn(Warning.of(scanOp.getSourceLocation(), ErrorCode.SAMPLE_HAS_ZERO_ROWS));
                     }
-                    finalDatasetCard *= predicateCardinality / sampleCard;
-                    // now switch the input back.
-                    parent.getInputs().get(0).setValue(scanOp);
+                }
+                finalDatasetCard *= predicateCardinality / sampleCard;
+                // now switch the input back.
+                parent.getInputs().get(0).setValue(scanOp);
+                if (jn.getCardinality() == jn.getOrigCardinality()) { // this means there was no selectivity hint provided
                     jn.setCardinality(finalDatasetCard);
-                    if (projectedSize > 0.0) {
-                        jn.setAvgDocSize(projectedSize);
-                    } else {
-                        ARecord record = (ARecord) (((IAObject) ((List<IAObject>) (result.get(0))).get(0)));
-                        int fields = record.numberOfFields();
-                        jn.setAvgDocSize(fields * 100); // cant think of anything better... cards are more important anyway
-                    }
                 }
+                jn.setAvgDocSize(projectedSize);
             }
             dataScanPlan = jn.addSingleDatasetPlans();
             if (dataScanPlan == PlanNode.NO_PLAN) {
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
index 364289c1e6..95f2da6845 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/Stats.java
@@ -101,6 +101,8 @@ public class Stats {
     protected Index findSampleIndex(DataSourceScanOperator scanOp, IOptimizationContext context)
             throws AlgebricksException {
         DataSource ds = (DataSource) scanOp.getDataSource();
+        if (ds.getDatasourceType() != DataSource.Type.INTERNAL_DATASET)
+            return null;
         DataSourceId dsid = ds.getId();
         MetadataProvider mdp = (MetadataProvider) context.getMetadataProvider();
         return mdp.findSampleIndex(dsid.getDatabaseName(), dsid.getDataverseName(), dsid.getDatasourceName());
@@ -542,6 +544,11 @@ public class Stats {
         return predicateCardinality;
     }
 
+    public int numberOfFields(List<List<IAObject>> result) {
+        ARecord record = (ARecord) (((IAObject) ((List<IAObject>) (result.get(0))).get(0)));
+        return record.numberOfFields();
+    }
+
     // Can have null returned, so this routine should only be called if at least tuple is returned by the sample
     public double findProjectedSize(List<List<IAObject>> result) {
         ARecord record = (ARecord) (((IAObject) ((List<IAObject>) (result.get(0))).get(0)));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.3.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.3.plan
index 68029ed319..cd3f2d4afa 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.3.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.3.plan
@@ -1,20 +1,20 @@
-distribute result [$$35] [cardinality: 959.81, op-cost: 0.0, total-cost: 136331.42]
+distribute result [$$35] [cardinality: 960.71, op-cost: 0.0, total-cost: 136471.34]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 959.81, op-cost: 0.0, total-cost: 136331.42]
+  exchange [cardinality: 960.71, op-cost: 0.0, total-cost: 136471.34]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    distinct ([$$35]) [cardinality: 959.81, op-cost: 58413.21, total-cost: 136331.42]
+    distinct ([$$35]) [cardinality: 960.71, op-cost: 58474.7, total-cost: 136471.34]
     -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-      exchange [cardinality: 4779.14, op-cost: 0.0, total-cost: 77918.21]
+      exchange [cardinality: 4783.64, op-cost: 0.0, total-cost: 77996.64]
       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-        order (ASC, $$35) [cardinality: 4779.14, op-cost: 58413.21, total-cost: 77918.21]
+        order (ASC, $$35) [cardinality: 4783.64, op-cost: 58474.7, total-cost: 77996.64]
         -- STABLE_SORT [$$35(ASC)]  |PARTITIONED|
-          exchange [cardinality: 4779.14, op-cost: 0.0, total-cost: 19505.0]
+          exchange [cardinality: 4783.64, op-cost: 0.0, total-cost: 19521.94]
           -- HASH_PARTITION_EXCHANGE [$$35]  |PARTITIONED|
-            project ([$$35]) [cardinality: 4779.14, op-cost: 0.0, total-cost: 19505.0]
+            project ([$$35]) [cardinality: 4783.64, op-cost: 0.0, total-cost: 19521.94]
             -- STREAM_PROJECT  |PARTITIONED|
-              assign [$$35] <- [{"l_linenumber": $$37, "l_partkey": $$l.getField(1), "o_custkey": $$o.getField(1)}] [cardinality: 4779.14, op-cost: 0.0, total-cost: 19505.0]
+              assign [$$35] <- [{"l_linenumber": $$37, "l_partkey": $$l.getField(1), "o_custkey": $$o.getField(1)}] [cardinality: 4783.64, op-cost: 0.0, total-cost: 19521.94]
               -- ASSIGN  |PARTITIONED|
-                select (gt($$l.getField(4), 10)) [cardinality: 4779.14, op-cost: 12005.0, total-cost: 19505.0]
+                select (gt($$l.getField(4), 10)) [cardinality: 4783.64, op-cost: 12016.29, total-cost: 19521.94]
                 -- STREAM_SELECT  |PARTITIONED|
                   project ([$$o, $$37, $$l]) [cardinality: 4779.14, op-cost: 0.0, total-cost: 6005.0]
                   -- STREAM_PROJECT  |PARTITIONED|
@@ -29,4 +29,4 @@ distribute result [$$35] [cardinality: 959.81, op-cost: 0.0, total-cost: 136331.
                             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                               empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.4.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.4.plan
index db7adea674..490133adb5 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.4.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.4.plan
@@ -1,22 +1,22 @@
-distribute result [$$34] [cardinality: 1399.06, op-cost: 0.0, total-cost: 166621.34]
+distribute result [$$34] [cardinality: 1400.38, op-cost: 0.0, total-cost: 166792.72]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 1399.06, op-cost: 0.0, total-cost: 166621.34]
+  exchange [cardinality: 1400.38, op-cost: 0.0, total-cost: 166792.72]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    distinct ([$$34]) [cardinality: 1399.06, op-cost: 73558.17, total-cost: 166621.34]
+    distinct ([$$34]) [cardinality: 1400.38, op-cost: 73635.39, total-cost: 166792.72]
     -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-      exchange [cardinality: 5875.07, op-cost: 0.0, total-cost: 93063.17]
+      exchange [cardinality: 5880.6, op-cost: 0.0, total-cost: 93157.33]
       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-        order (ASC, $$34) [cardinality: 5875.07, op-cost: 73558.17, total-cost: 93063.17]
+        order (ASC, $$34) [cardinality: 5880.6, op-cost: 73635.39, total-cost: 93157.33]
         -- STABLE_SORT [$$34(ASC)]  |PARTITIONED|
-          exchange [cardinality: 5875.07, op-cost: 0.0, total-cost: 19505.0]
+          exchange [cardinality: 5880.6, op-cost: 0.0, total-cost: 19521.94]
           -- HASH_PARTITION_EXCHANGE [$$34]  |PARTITIONED|
-            project ([$$34]) [cardinality: 5875.07, op-cost: 0.0, total-cost: 19505.0]
+            project ([$$34]) [cardinality: 5880.6, op-cost: 0.0, total-cost: 19521.94]
             -- STREAM_PROJECT  |PARTITIONED|
-              assign [$$34] <- [{"l_orderkey": $$36, "o_custkey": $$o.getField(1)}] [cardinality: 5875.07, op-cost: 0.0, total-cost: 19505.0]
+              assign [$$34] <- [{"l_orderkey": $$36, "o_custkey": $$o.getField(1)}] [cardinality: 5880.6, op-cost: 0.0, total-cost: 19521.94]
               -- ASSIGN  |PARTITIONED|
-                project ([$$o, $$36]) [cardinality: 5875.07, op-cost: 0.0, total-cost: 19505.0]
+                project ([$$o, $$36]) [cardinality: 5880.6, op-cost: 0.0, total-cost: 19521.94]
                 -- STREAM_PROJECT  |PARTITIONED|
-                  select (gt($$l.getField(1), 5)) [cardinality: 5875.07, op-cost: 12005.0, total-cost: 19505.0]
+                  select (gt($$l.getField(1), 5)) [cardinality: 5880.6, op-cost: 12016.29, total-cost: 19521.94]
                   -- STREAM_SELECT  |PARTITIONED|
                     project ([$$o, $$36, $$l]) [cardinality: 5875.07, op-cost: 0.0, total-cost: 6005.0]
                     -- STREAM_PROJECT  |PARTITIONED|
@@ -31,4 +31,4 @@ distribute result [$$34] [cardinality: 1399.06, op-cost: 0.0, total-cost: 166621
                               exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                 empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.5.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.5.plan
index 6ce04becb0..1526603007 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.5.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.5.plan
@@ -1,42 +1,42 @@
-distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+distribute result [$$101] [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+  exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$101]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+    project ([$$101]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$101] <- [{"$1": $$111}] [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+      assign [$$101] <- [{"$1": $$111}] [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
       -- ASSIGN  |PARTITIONED|
-        project ([$$111]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+        project ([$$111]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
         -- STREAM_PROJECT  |PARTITIONED|
-          exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015.0]
+          exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 18037.6]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$l_partkey := $$115; $$o_orderstatus := $$116; $$c_nationkey := $$117]) decor ([]) {
                       aggregate [$$111] <- [sql-sum-serial($$114)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
                         nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 18015.0]
+                   } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 18037.6]
             -- EXTERNAL_GROUP_BY[$$115, $$116, $$117]  |PARTITIONED|
-              exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 12010.0]
+              exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 12021.3]
               -- HASH_PARTITION_EXCHANGE [$$115, $$116, $$117]  |PARTITIONED|
                 group by ([$$115 := $$102; $$116 := $$103; $$117 := $$104]) decor ([]) {
                           aggregate [$$114] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- AGGREGATE  |LOCAL|
                             nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                             -- NESTED_TUPLE_SOURCE  |LOCAL|
-                       } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 12010.0]
+                       } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 12021.3]
                 -- EXTERNAL_GROUP_BY[$$102, $$103, $$104]  |PARTITIONED|
-                  exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                  exchange [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    project ([$$102, $$103, $$104]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                    project ([$$102, $$103, $$104]) [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                     -- STREAM_PROJECT  |PARTITIONED|
-                      assign [$$102] <- [$$l.getField(1)] [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                      assign [$$102] <- [$$l.getField(1)] [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                       -- ASSIGN  |PARTITIONED|
-                        project ([$$103, $$104, $$l]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                        project ([$$103, $$104, $$l]) [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                          exchange [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6005.0, op-cost: 6005.0, total-cost: 6005.0]
+                            unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6010.65, op-cost: 6005.0, total-cost: 6005.0]
                             -- BTREE_SEARCH  |PARTITIONED|
                               exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                               -- BROADCAST_EXCHANGE  |PARTITIONED|
@@ -44,7 +44,7 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015
                                 -- STREAM_PROJECT  |PARTITIONED|
                                   exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    join (eq($$109, $$108)) [cardinality: 1500.0, op-cost: 2100.0, total-cost: 4350.0]
+                                    join (eq($$109, $$108)) [cardinality: 1501.41, op-cost: 2101.41, total-cost: 4351.41]
                                     -- HYBRID_HASH_JOIN [$$109][$$108]  |PARTITIONED|
                                       exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -73,4 +73,4 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 18015
                                                 exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                                   empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.6.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.6.plan
index d689ae210f..792ea6b0eb 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.6.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.6.plan
@@ -1,38 +1,38 @@
-distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+distribute result [$$101] [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+  exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$101]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+    project ([$$101]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$101] <- [{"$1": $$111}] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+      assign [$$101] <- [{"$1": $$111}] [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
       -- ASSIGN  |PARTITIONED|
-        project ([$$111]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+        project ([$$111]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
         -- STREAM_PROJECT  |PARTITIONED|
-          exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+          exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$l_linenumber := $$115; $$o_orderstatus := $$116; $$c_nationkey := $$117]) decor ([]) {
                       aggregate [$$111] <- [sql-sum-serial($$114)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
                         nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 34365.0]
+                   } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 34405.95]
             -- EXTERNAL_GROUP_BY[$$115, $$116, $$117]  |PARTITIONED|
-              exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 28360.0]
+              exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 28389.65]
               -- HASH_PARTITION_EXCHANGE [$$115, $$116, $$117]  |PARTITIONED|
                 group by ([$$115 := $$106; $$116 := $$103; $$117 := $$104]) decor ([]) {
                           aggregate [$$114] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- AGGREGATE  |LOCAL|
                             nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                             -- NESTED_TUPLE_SOURCE  |LOCAL|
-                       } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 28360.0]
+                       } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 28389.65]
                 -- EXTERNAL_GROUP_BY[$$106, $$103, $$104]  |PARTITIONED|
-                  exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                  exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    project ([$$106, $$103, $$104]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                    project ([$$106, $$103, $$104]) [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                     -- STREAM_PROJECT  |PARTITIONED|
-                      exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                      exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6005.0, op-cost: 12005.0, total-cost: 22355.0]
+                        unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6016.3, op-cost: 12016.29, total-cost: 22373.35]
                         -- BTREE_SEARCH  |PARTITIONED|
                           exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- BROADCAST_EXCHANGE  |PARTITIONED|
@@ -40,7 +40,7 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365
                             -- STREAM_PROJECT  |PARTITIONED|
                               exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                join (eq($$109, $$108)) [cardinality: 1500.0, op-cost: 2100.0, total-cost: 4350.0]
+                                join (eq($$109, $$108)) [cardinality: 1501.41, op-cost: 2101.41, total-cost: 4351.41]
                                 -- HYBRID_HASH_JOIN [$$109][$$108]  |PARTITIONED|
                                   exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -69,4 +69,4 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365
                                             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                               empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.7.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.7.plan
index b3e56b835f..af17e0ffb6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.7.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.7.plan
@@ -1,38 +1,38 @@
-distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+distribute result [$$101] [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+  exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$101]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+    project ([$$101]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$101] <- [{"$1": $$111}] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+      assign [$$101] <- [{"$1": $$111}] [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
       -- ASSIGN  |PARTITIONED|
-        project ([$$111]) [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+        project ([$$111]) [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
         -- STREAM_PROJECT  |PARTITIONED|
-          exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365.0]
+          exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 34405.95]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$l_linenumber := $$115; $$c_nationkey := $$116; $$o_orderstatus := $$117]) decor ([]) {
                       aggregate [$$111] <- [sql-sum-serial($$114)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
                         nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 34365.0]
+                   } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 34405.95]
             -- EXTERNAL_GROUP_BY[$$115, $$116, $$117]  |PARTITIONED|
-              exchange [cardinality: 1000.83, op-cost: 0.0, total-cost: 28360.0]
+              exchange [cardinality: 1002.74, op-cost: 0.0, total-cost: 28389.65]
               -- HASH_PARTITION_EXCHANGE [$$115, $$116, $$117]  |PARTITIONED|
                 group by ([$$115 := $$106; $$116 := $$103; $$117 := $$104]) decor ([]) {
                           aggregate [$$114] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- AGGREGATE  |LOCAL|
                             nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                             -- NESTED_TUPLE_SOURCE  |LOCAL|
-                       } [cardinality: 1000.83, op-cost: 6005.0, total-cost: 28360.0]
+                       } [cardinality: 1002.74, op-cost: 6016.3, total-cost: 28389.65]
                 -- EXTERNAL_GROUP_BY[$$106, $$103, $$104]  |PARTITIONED|
-                  exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                  exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                    project ([$$106, $$103, $$104]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                    project ([$$106, $$103, $$104]) [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                     -- STREAM_PROJECT  |PARTITIONED|
-                      exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22355.0]
+                      exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22373.35]
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6005.0, op-cost: 12005.0, total-cost: 22355.0]
+                        unnest-map [$$105, $$106, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$107, 1, $$107, true, true, true) [cardinality: 6016.3, op-cost: 12016.29, total-cost: 22373.35]
                         -- BTREE_SEARCH  |PARTITIONED|
                           exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- BROADCAST_EXCHANGE  |PARTITIONED|
@@ -40,7 +40,7 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365
                             -- STREAM_PROJECT  |PARTITIONED|
                               exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                join (eq($$109, $$108)) [cardinality: 1500.0, op-cost: 2100.0, total-cost: 4350.0]
+                                join (eq($$109, $$108)) [cardinality: 1501.41, op-cost: 2101.41, total-cost: 4351.41]
                                 -- HYBRID_HASH_JOIN [$$109][$$108]  |PARTITIONED|
                                   exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -69,4 +69,4 @@ distribute result [$$101] [cardinality: 1000.83, op-cost: 0.0, total-cost: 34365
                                             exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                               empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.8.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.8.plan
index 7bc07c2f84..7db992d4c4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.8.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/cardinality-estimation/join-queries/join-queries.8.plan
@@ -1,48 +1,48 @@
-distribute result [$$119] [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
+distribute result [$$119] [cardinality: 25.0, op-cost: 0.0, total-cost: 7087.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
+  exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 7087.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$119]) [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
+    project ([$$119]) [cardinality: 25.0, op-cost: 0.0, total-cost: 7087.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$119] <- [{"n_name": $$n_name, "revenue": $$132}] [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
+      assign [$$119] <- [{"n_name": $$n_name, "revenue": $$132}] [cardinality: 25.0, op-cost: 0.0, total-cost: 7087.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
+        exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 7087.0]
         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
           group by ([$$n_name := $$142]) decor ([]) {
                     aggregate [$$132] <- [global-sql-sum-serial($$141)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- AGGREGATE  |LOCAL|
                       nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- NESTED_TUPLE_SOURCE  |LOCAL|
-                 } [cardinality: 25.0, op-cost: 99.42, total-cost: 7085.86]
+                 } [cardinality: 25.0, op-cost: 99.52, total-cost: 7087.0]
           -- EXTERNAL_GROUP_BY[$$142]  |PARTITIONED|
-            exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 6986.44]
+            exchange [cardinality: 25.0, op-cost: 0.0, total-cost: 6987.48]
             -- HASH_PARTITION_EXCHANGE [$$142]  |PARTITIONED|
               group by ([$$142 := $$120]) decor ([]) {
                         aggregate [$$141] <- [local-sql-sum-serial(numeric-multiply($$139, numeric-subtract(1, $$140)))] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 25.0, op-cost: 99.42, total-cost: 6986.44]
+                     } [cardinality: 25.0, op-cost: 99.52, total-cost: 6987.48]
               -- EXTERNAL_GROUP_BY[$$120]  |PARTITIONED|
-                exchange [cardinality: 99.42, op-cost: 0.0, total-cost: 6887.02]
+                exchange [cardinality: 99.52, op-cost: 0.0, total-cost: 6887.96]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  project ([$$139, $$140, $$120]) [cardinality: 99.42, op-cost: 0.0, total-cost: 6887.02]
+                  project ([$$139, $$140, $$120]) [cardinality: 99.52, op-cost: 0.0, total-cost: 6887.96]
                   -- STREAM_PROJECT  |PARTITIONED|
-                    exchange [cardinality: 99.42, op-cost: 0.0, total-cost: 6887.02]
+                    exchange [cardinality: 99.52, op-cost: 0.0, total-cost: 6887.96]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      join (and(eq($$130, $$128), eq($$133, $$127))) [cardinality: 99.42, op-cost: 1034.24, total-cost: 6887.02]
+                      join (and(eq($$130, $$128), eq($$133, $$127))) [cardinality: 99.52, op-cost: 1035.18, total-cost: 6887.96]
                       -- HYBRID_HASH_JOIN [$$128, $$133][$$130, $$127]  |PARTITIONED|
-                        exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                        exchange [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          project ([$$139, $$140, $$120, $$128, $$133]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                          project ([$$139, $$140, $$120, $$128, $$133]) [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                           -- STREAM_PROJECT  |PARTITIONED|
-                            assign [$$140, $$139, $$133] <- [$$l.getField(6), $$l.getField(5), $$l.getField(2)] [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                            assign [$$140, $$139, $$133] <- [$$l.getField(6), $$l.getField(5), $$l.getField(2)] [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                             -- ASSIGN  |PARTITIONED|
-                              project ([$$120, $$128, $$l]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                              project ([$$120, $$128, $$l]) [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                               -- STREAM_PROJECT  |PARTITIONED|
-                                exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
+                                exchange [cardinality: 6010.65, op-cost: 0.0, total-cost: 6005.0]
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                  unnest-map [$$125, $$126, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$124, 1, $$124, true, true, true) [cardinality: 6005.0, op-cost: 6005.0, total-cost: 6005.0]
+                                  unnest-map [$$125, $$126, $$l] <- index-search("LineItem", 0, "Default", "tpch", "LineItem", true, true, 1, $$124, 1, $$124, true, true, true) [cardinality: 6010.65, op-cost: 6005.0, total-cost: 6005.0]
                                   -- BTREE_SEARCH  |PARTITIONED|
                                     exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                     -- BROADCAST_EXCHANGE  |PARTITIONED|
@@ -119,4 +119,4 @@ distribute result [$$119] [cardinality: 25.0, op-cost: 0.0, total-cost: 7085.86]
                                   exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                     empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                    -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
+                                    -- 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 42787f396d..70813fabab 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,24 +1,24 @@
-distribute result [$$36] [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.45]
+distribute result [$$36] [cardinality: 6016.3, op-cost: 0.0, total-cost: 98061.73]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.45]
+  exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 98061.73]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$36]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.45]
+    project ([$$36]) [cardinality: 6016.3, op-cost: 0.0, total-cost: 98061.73]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$36] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": $$42}] [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.45]
+      assign [$$36] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": $$42}] [cardinality: 6016.3, op-cost: 0.0, total-cost: 98061.73]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.45]
+        exchange [cardinality: 6016.3, 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: 6005.0, op-cost: 75374.45, total-cost: 97889.45]
+          order (ASC, $$43) (ASC, $$44) (ASC, $$42) [cardinality: 6016.3, op-cost: 75532.61, total-cost: 98061.73]
           -- STABLE_SORT [$$43(ASC), $$44(ASC), $$42(ASC)]  |PARTITIONED|
-            exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22515.0]
+            exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22529.12]
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              project ([$$43, $$44, $$42]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 22515.0]
+              project ([$$43, $$44, $$42]) [cardinality: 6016.3, op-cost: 0.0, total-cost: 22529.12]
               -- STREAM_PROJECT  |PARTITIONED|
-                exchange [cardinality: 6005.0, op-cost: 0.0, total-cost: 22515.0]
+                exchange [cardinality: 6016.3, op-cost: 0.0, total-cost: 22529.12]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  join (and(eq($$43, $$44), eq($$49, $$42))) [cardinality: 6005.0, op-cost: 7505.0, total-cost: 22515.0]
+                  join (and(eq($$43, $$44), eq($$49, $$42))) [cardinality: 6016.3, op-cost: 7512.06, total-cost: 22529.12]
                   -- HYBRID_HASH_JOIN [$$44, $$42][$$43, $$49]  |PARTITIONED|
-                    exchange [cardinality: 6005.0, op-cost: 6005.0, total-cost: 12010.0]
+                    exchange [cardinality: 6005.0, op-cost: 6010.65, total-cost: 12015.65]
                     -- HASH_PARTITION_EXCHANGE [$$44, $$42]  |PARTITIONED|
                       project ([$$44, $$42]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
                       -- STREAM_PROJECT  |PARTITIONED|
@@ -26,7 +26,7 @@ distribute result [$$36] [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.4
                         -- ASSIGN  |PARTITIONED|
                           project ([$$44, $$l]) [cardinality: 6005.0, op-cost: 0.0, total-cost: 6005.0]
                           -- STREAM_PROJECT  |PARTITIONED|
-                            exchange [cardinality: 6005.0, op-cost: 6005.0, total-cost: 12010.0]
+                            exchange [cardinality: 6005.0, op-cost: 6010.65, total-cost: 12015.65]
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                               data-scan []<-[$$44, $$45, $$l] <- tpch.LineItem [cardinality: 6005.0, op-cost: 6005.0, total-cost: 6005.0]
                               -- DATASOURCE_SCAN  |PARTITIONED|
@@ -34,13 +34,13 @@ distribute result [$$36] [cardinality: 6005.0, op-cost: 0.0, total-cost: 97889.4
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                                   empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                                   -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                    exchange [cardinality: 1500.0, op-cost: 1500.0, total-cost: 3000.0]
+                    exchange [cardinality: 1500.0, op-cost: 1501.41, total-cost: 3001.41]
                     -- HASH_PARTITION_EXCHANGE [$$43, $$49]  |PARTITIONED|
                       assign [$$49] <- [$$43] [cardinality: 1500.0, op-cost: 0.0, total-cost: 1500.0]
                       -- ASSIGN  |PARTITIONED|
                         project ([$$43]) [cardinality: 1500.0, op-cost: 0.0, total-cost: 1500.0]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange [cardinality: 1500.0, op-cost: 1500.0, total-cost: 3000.0]
+                          exchange [cardinality: 1500.0, op-cost: 1501.41, total-cost: 3001.41]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                             data-scan []<-[$$43, $$o] <- tpch.Orders [cardinality: 1500.0, op-cost: 1500.0, total-cost: 1500.0]
                             -- DATASOURCE_SCAN  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.08.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.08.plan
index ff45113a9f..0668ea4441 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.08.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/join/hash-join-with-redundant-variable/hash-join-with-redundant-variable.08.plan
@@ -1,14 +1,14 @@
-distribute result [$$38] [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.45]
+distribute result [$$38] [cardinality: 1500.0, op-cost: 0.0, total-cost: 77032.61]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.45]
+  exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 77032.61]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$38]) [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.45]
+    project ([$$38]) [cardinality: 1500.0, op-cost: 0.0, total-cost: 77032.61]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$38] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": $$47}] [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.45]
+      assign [$$38] <- [{"o_orderkey": $$43, "l_orderkey": $$44, "l_suppkey": $$47}] [cardinality: 1500.0, op-cost: 0.0, total-cost: 77032.61]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.45]
+        exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 77032.61]
         -- SORT_MERGE_EXCHANGE [$$43(ASC), $$44(ASC), $$47(ASC) ]  |PARTITIONED|
-          order (ASC, $$43) (ASC, $$44) (ASC, $$47) [cardinality: 1500.0, op-cost: 75374.45, total-cost: 76874.45]
+          order (ASC, $$43) (ASC, $$44) (ASC, $$47) [cardinality: 1500.0, op-cost: 75532.61, total-cost: 77032.61]
           -- STABLE_SORT [$$43(ASC), $$44(ASC), $$47(ASC)]  |PARTITIONED|
             exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 1500.0]
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -16,7 +16,7 @@ distribute result [$$38] [cardinality: 1500.0, op-cost: 0.0, total-cost: 76874.4
               -- STREAM_PROJECT  |PARTITIONED|
                 exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 1500.0]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                  left outer join (and(eq($$43, $$44), eq($$56, $$47))) [cardinality: 6005.0, op-cost: 7505.0, total-cost: 22515.0]
+                  left outer join (and(eq($$43, $$44), eq($$56, $$47))) [cardinality: 6016.3, op-cost: 7512.06, total-cost: 22529.12]
                   -- HYBRID_HASH_JOIN [$$43, $$56][$$44, $$47]  |PARTITIONED|
                     exchange [cardinality: 1500.0, op-cost: 0.0, total-cost: 1500.0]
                     -- HASH_PARTITION_EXCHANGE [$$43, $$56]  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.024.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.024.plan
index 721e547926..a00d7f6223 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.024.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.024.plan
@@ -1,18 +1,18 @@
-distribute result [$$v] [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+distribute result [$$v] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$v]) [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+    project ([$$v]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$v] <- [{"SK0": $$14, "PK0": $$15}] [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+      assign [$$v] <- [{"SK0": $$14, "PK0": $$15}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$15(ASC) ]  |PARTITIONED|
-          order (ASC, $$15) [cardinality: 14.0, op-cost: 53.3, total-cost: 67.3]
+          order (ASC, $$15) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
           -- STABLE_SORT [$$15(ASC)]  |PARTITIONED|
-            exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              data-scan []<-[$$14, $$15] <- test.ds1.ds1_age.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
+              data-scan []<-[$$14, $$15] <- test.ds1.ds1_age.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
               -- DATASOURCE_SCAN  |PARTITIONED|
                 exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.025.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.025.plan
index 0e5079f0bb..631c16c0f3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.025.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.025.plan
@@ -1,18 +1,18 @@
-distribute result [$$v] [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+distribute result [$$v] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$v]) [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+    project ([$$v]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$v] <- [{"SK0": $$14, "SK1": $$15, "PK0": $$16}] [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+      assign [$$v] <- [{"SK0": $$14, "SK1": $$15, "PK0": $$16}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 67.3]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$16(ASC) ]  |PARTITIONED|
-          order (ASC, $$16) [cardinality: 14.0, op-cost: 53.3, total-cost: 67.3]
+          order (ASC, $$16) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
           -- STABLE_SORT [$$16(ASC)]  |PARTITIONED|
-            exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              data-scan []<-[$$14, $$15, $$16] <- test.ds1.ds1_age_dept.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
+              data-scan []<-[$$14, $$15, $$16] <- test.ds1.ds1_age_dept.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
               -- DATASOURCE_SCAN  |PARTITIONED|
                 exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.026.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.026.plan
index e9f57a14a9..9a21589d1e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.026.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.026.plan
@@ -1,42 +1,38 @@
-distribute result [$$57] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+distribute result [$$57] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$57]) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+    project ([$$57]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$57] <- [{"age": $$SK0, "dept": $$SK1, "cnt": $$63}] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+      assign [$$57] <- [{"age": $$SK0, "dept": $$SK1, "cnt": $$63}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$SK1(ASC), $$SK0(ASC) ]  |PARTITIONED|
-          order (ASC, $$SK1) (ASC, $$SK0) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-          -- STABLE_SORT [$$SK1(ASC), $$SK0(ASC)]  |PARTITIONED|
-            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              group by ([$$SK1 := $$65; $$SK0 := $$66]) decor ([]) {
-                        aggregate [$$63] <- [sql-sum-serial($$64)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          group by ([$$SK1 := $$65; $$SK0 := $$66]) decor ([]) {
+                    aggregate [$$63] <- [agg-sql-sum($$64)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                    -- AGGREGATE  |LOCAL|
+                      nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- NESTED_TUPLE_SOURCE  |LOCAL|
+                 } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- SORT_GROUP_BY[$$65, $$66]  |PARTITIONED|
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- HASH_PARTITION_EXCHANGE [$$65, $$66]  |PARTITIONED|
+              group by ([$$65 := $$61; $$66 := $$60]) decor ([]) {
+                        aggregate [$$64] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 0.0, op-cost: 14.0, total-cost: 42.0]
-              -- EXTERNAL_GROUP_BY[$$65, $$66]  |PARTITIONED|
-                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 28.0]
-                -- HASH_PARTITION_EXCHANGE [$$65, $$66]  |PARTITIONED|
-                  group by ([$$65 := $$61; $$66 := $$60]) decor ([]) {
-                            aggregate [$$64] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- AGGREGATE  |LOCAL|
-                              nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                         } [cardinality: 0.0, op-cost: 14.0, total-cost: 28.0]
-                  -- EXTERNAL_GROUP_BY[$$61, $$60]  |PARTITIONED|
-                    exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                     } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- SORT_GROUP_BY[$$61, $$60]  |PARTITIONED|
+                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  project ([$$61, $$60]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      project ([$$61, $$60]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                      data-scan []<-[$$60, $$61, $$62] <- test.ds1.ds1_age_dept.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$60, $$61, $$62] <- test.ds1.ds1_age_dept.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                          empty-tuple-source [cardinality: 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/query_index/q01/q01.027.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.027.plan
index f3a257e734..2c2859469c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.027.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.027.plan
@@ -1,20 +1,20 @@
-distribute result [$$33] [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+distribute result [$$33] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    project ([$$33]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+    project ([$$33]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |UNPARTITIONED|
-      assign [$$33] <- [{"cnt": $$36}] [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+      assign [$$33] <- [{"cnt": $$36}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |UNPARTITIONED|
-        aggregate [$$36] <- [agg-sql-sum($$37)] [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+        aggregate [$$36] <- [agg-sql-sum($$37)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- AGGREGATE  |UNPARTITIONED|
-          exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+          exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
           -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
-            aggregate [$$37] <- [agg-sql-count(1)] [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+            aggregate [$$37] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
             -- AGGREGATE  |PARTITIONED|
-              exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+              exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                data-scan []<-[$$34, $$35] <- test.ds1.ds1_dept.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
+                data-scan []<-[$$34, $$35] <- test.ds1.ds1_dept.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                 -- DATASOURCE_SCAN  |PARTITIONED|
                   exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.028.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.028.plan
index 6cc5020e0e..f171976a23 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.028.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.028.plan
@@ -1,42 +1,38 @@
-distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$45] <- [{"age": $$SK0, "cnt": $$49}] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+      assign [$$45] <- [{"age": $$SK0, "cnt": $$49}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$SK0(ASC) ]  |PARTITIONED|
-          order (ASC, $$SK0) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-          -- STABLE_SORT [$$SK0(ASC)]  |PARTITIONED|
-            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              group by ([$$SK0 := $$51]) decor ([]) {
-                        aggregate [$$49] <- [sql-sum-serial($$50)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          group by ([$$SK0 := $$51]) decor ([]) {
+                    aggregate [$$49] <- [agg-sql-sum($$50)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                    -- AGGREGATE  |LOCAL|
+                      nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- NESTED_TUPLE_SOURCE  |LOCAL|
+                 } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- SORT_GROUP_BY[$$51]  |PARTITIONED|
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- HASH_PARTITION_EXCHANGE [$$51]  |PARTITIONED|
+              group by ([$$51 := $$47]) decor ([]) {
+                        aggregate [$$50] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 0.0, op-cost: 14.0, total-cost: 42.0]
-              -- EXTERNAL_GROUP_BY[$$51]  |PARTITIONED|
-                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 28.0]
-                -- HASH_PARTITION_EXCHANGE [$$51]  |PARTITIONED|
-                  group by ([$$51 := $$47]) decor ([]) {
-                            aggregate [$$50] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- AGGREGATE  |LOCAL|
-                              nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                         } [cardinality: 0.0, op-cost: 14.0, total-cost: 28.0]
-                  -- EXTERNAL_GROUP_BY[$$47]  |PARTITIONED|
-                    exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                     } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- PRE_CLUSTERED_GROUP_BY[$$47]  |PARTITIONED|
+                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  project ([$$47]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      project ([$$47]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                      data-scan []<-[$$47, $$48] <- test.ds1.ds1_age.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$47, $$48] <- test.ds1.ds1_age.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                          empty-tuple-source [cardinality: 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/query_index/q01/q01.029.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.029.plan
index 27816a116c..ed25d3ada2 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.029.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.029.plan
@@ -1,42 +1,38 @@
-distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$45] <- [{"age": $$SK0, "cnt": $$50}] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+      assign [$$45] <- [{"age": $$SK0, "cnt": $$50}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$SK0(ASC) ]  |PARTITIONED|
-          order (ASC, $$SK0) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-          -- STABLE_SORT [$$SK0(ASC)]  |PARTITIONED|
-            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              group by ([$$SK0 := $$52]) decor ([]) {
-                        aggregate [$$50] <- [sql-sum-serial($$51)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          group by ([$$SK0 := $$52]) decor ([]) {
+                    aggregate [$$50] <- [agg-sql-sum($$51)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                    -- AGGREGATE  |LOCAL|
+                      nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- NESTED_TUPLE_SOURCE  |LOCAL|
+                 } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- SORT_GROUP_BY[$$52]  |PARTITIONED|
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- HASH_PARTITION_EXCHANGE [$$52]  |PARTITIONED|
+              group by ([$$52 := $$47]) decor ([]) {
+                        aggregate [$$51] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 0.0, op-cost: 14.0, total-cost: 42.0]
-              -- EXTERNAL_GROUP_BY[$$52]  |PARTITIONED|
-                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 28.0]
-                -- HASH_PARTITION_EXCHANGE [$$52]  |PARTITIONED|
-                  group by ([$$52 := $$47]) decor ([]) {
-                            aggregate [$$51] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- AGGREGATE  |LOCAL|
-                              nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                         } [cardinality: 0.0, op-cost: 14.0, total-cost: 28.0]
-                  -- EXTERNAL_GROUP_BY[$$47]  |PARTITIONED|
-                    exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                     } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- PRE_CLUSTERED_GROUP_BY[$$47]  |PARTITIONED|
+                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  project ([$$47]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      project ([$$47]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                      data-scan []<-[$$47, $$48, $$49] <- test.ds1.ds1_age_dept.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$47, $$48, $$49] <- test.ds1.ds1_age_dept.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                          empty-tuple-source [cardinality: 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/query_index/q01/q01.030.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.030.plan
index 39dc701aaf..05dc8da520 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.030.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.030.plan
@@ -1,42 +1,38 @@
-distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+distribute result [$$45] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+    project ([$$45]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$45] <- [{"age": $$SK1, "cnt": $$50}] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+      assign [$$45] <- [{"age": $$SK1, "cnt": $$50}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$SK1(ASC) ]  |PARTITIONED|
-          order (ASC, $$SK1) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-          -- STABLE_SORT [$$SK1(ASC)]  |PARTITIONED|
-            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              group by ([$$SK1 := $$52]) decor ([]) {
-                        aggregate [$$50] <- [sql-sum-serial($$51)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          group by ([$$SK1 := $$52]) decor ([]) {
+                    aggregate [$$50] <- [agg-sql-sum($$51)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                    -- AGGREGATE  |LOCAL|
+                      nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- NESTED_TUPLE_SOURCE  |LOCAL|
+                 } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- SORT_GROUP_BY[$$52]  |PARTITIONED|
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- HASH_PARTITION_EXCHANGE [$$52]  |PARTITIONED|
+              group by ([$$52 := $$48]) decor ([]) {
+                        aggregate [$$51] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 0.0, op-cost: 14.0, total-cost: 42.0]
-              -- EXTERNAL_GROUP_BY[$$52]  |PARTITIONED|
-                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 28.0]
-                -- HASH_PARTITION_EXCHANGE [$$52]  |PARTITIONED|
-                  group by ([$$52 := $$48]) decor ([]) {
-                            aggregate [$$51] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- AGGREGATE  |LOCAL|
-                              nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                         } [cardinality: 0.0, op-cost: 14.0, total-cost: 28.0]
-                  -- EXTERNAL_GROUP_BY[$$48]  |PARTITIONED|
-                    exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                     } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- SORT_GROUP_BY[$$48]  |PARTITIONED|
+                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  project ([$$48]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      project ([$$48]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                      data-scan []<-[$$47, $$48, $$49] <- test.ds1.ds1_dept_age.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$47, $$48, $$49] <- test.ds1.ds1_dept_age.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                          empty-tuple-source [cardinality: 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/query_index/q01/q01.031.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.031.plan
index d7395fba2b..42f59402fd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.031.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/query_index/q01/q01.031.plan
@@ -1,42 +1,38 @@
-distribute result [$$57] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+distribute result [$$57] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+  exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    project ([$$57]) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+    project ([$$57]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- STREAM_PROJECT  |PARTITIONED|
-      assign [$$57] <- [{"age": $$SK0, "dept": $$SK1, "cnt": $$63}] [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+      assign [$$57] <- [{"age": $$SK0, "dept": $$SK1, "cnt": $$63}] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- ASSIGN  |PARTITIONED|
-        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
+        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
         -- SORT_MERGE_EXCHANGE [$$SK0(ASC), $$SK1(ASC) ]  |PARTITIONED|
-          order (ASC, $$SK0) (ASC, $$SK1) [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-          -- STABLE_SORT [$$SK0(ASC), $$SK1(ASC)]  |PARTITIONED|
-            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 42.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              group by ([$$SK0 := $$65; $$SK1 := $$66]) decor ([]) {
-                        aggregate [$$63] <- [sql-sum-serial($$64)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          group by ([$$SK0 := $$65; $$SK1 := $$66]) decor ([]) {
+                    aggregate [$$63] <- [agg-sql-sum($$64)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                    -- AGGREGATE  |LOCAL|
+                      nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- NESTED_TUPLE_SOURCE  |LOCAL|
+                 } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- SORT_GROUP_BY[$$65, $$66]  |PARTITIONED|
+            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- HASH_PARTITION_EXCHANGE [$$65, $$66]  |PARTITIONED|
+              group by ([$$65 := $$60; $$66 := $$61]) decor ([]) {
+                        aggregate [$$64] <- [agg-sql-count(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- AGGREGATE  |LOCAL|
                           nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                           -- NESTED_TUPLE_SOURCE  |LOCAL|
-                     } [cardinality: 0.0, op-cost: 14.0, total-cost: 42.0]
-              -- EXTERNAL_GROUP_BY[$$65, $$66]  |PARTITIONED|
-                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 28.0]
-                -- HASH_PARTITION_EXCHANGE [$$65, $$66]  |PARTITIONED|
-                  group by ([$$65 := $$60; $$66 := $$61]) decor ([]) {
-                            aggregate [$$64] <- [sql-count-serial(1)] [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- AGGREGATE  |LOCAL|
-                              nested tuple source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                         } [cardinality: 0.0, op-cost: 14.0, total-cost: 28.0]
-                  -- EXTERNAL_GROUP_BY[$$60, $$61]  |PARTITIONED|
-                    exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                     } [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- PRE_CLUSTERED_GROUP_BY[$$60, $$61]  |PARTITIONED|
+                exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  project ([$$60, $$61]) [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      project ([$$60, $$61]) [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange [cardinality: 14.0, op-cost: 0.0, total-cost: 14.0]
+                      data-scan []<-[$$60, $$61, $$62] <- test.ds1.ds1_age_dept.query-index [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      -- DATASOURCE_SCAN  |PARTITIONED|
+                        exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$60, $$61, $$62] <- test.ds1.ds1_age_dept.query-index [cardinality: 14.0, op-cost: 14.0, total-cost: 14.0]
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                          empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- EMPTY_TUPLE_SOURCE  |PARTITIONED|