You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by al...@apache.org on 2026/09/26 04:04:17 UTC

(asterixdb) branch master updated: [ASTERIXDB-3830][COMP] Enable hash-based COUNT(DISTINCT) by default

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

asf-gitbox-commits 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 f7f02cf4fe [ASTERIXDB-3830][COMP] Enable hash-based COUNT(DISTINCT) by default
f7f02cf4fe is described below

commit f7f02cf4fe3532b6dae006163b156837870f6da4
Author: Shahrzad Shirazi <Sh...@couchbase.com>
AuthorDate: Thu Sep 10 15:29:13 2026 -0700

    [ASTERIXDB-3830][COMP] Enable hash-based COUNT(DISTINCT) by default
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Ext-ref: MB-73960
    
    Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
    Change-Id: I3abfe8c99e68959a20c1b0a7022b698dec75db30
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/21739
    Reviewed-by: Ali Alsuliman <al...@gmail.com>
    Tested-by: Ali Alsuliman <al...@gmail.com>
---
 .../rules/RewriteCountDistinctToHashRule.java      | 12 +--
 .../distinct_mixed/distinct_mixed.3.plan           | 62 +++++++---------
 .../distinct_mixed/distinct_mixed.9.plan           | 22 ++----
 .../results/cbo-join/computed-join-predicate.plan  | 26 +------
 .../resources/optimizerts/results/ch2/ch2_q16.plan | 14 +---
 .../distinct_mixed/distinct_mixed.9.plan           | 22 ++----
 .../cbo-join/computed-join-predicate.plan          | 26 +------
 .../optimizerts/results_cbo/ch2/ch2_q16.plan       | 86 ++++++++++------------
 .../api/cluster_state_1/cluster_state_1.1.regexadm |  2 +-
 .../cluster_state_1_full.1.regexadm                |  2 +-
 .../cluster_state_1_less.1.regexadm                |  2 +-
 .../other-pushdowns/other-pushdowns.020.plan       | 74 +++++++++----------
 .../other-pushdowns/other-pushdowns.021.plan       | 74 +++++++++----------
 .../other-pushdowns/other-pushdowns.020.plan       | 78 +++++++++-----------
 .../other-pushdowns/other-pushdowns.021.plan       | 78 +++++++++-----------
 .../algebricks/core/config/AlgebricksConfig.java   |  2 +-
 16 files changed, 233 insertions(+), 349 deletions(-)

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RewriteCountDistinctToHashRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RewriteCountDistinctToHashRule.java
index f242082947..1dcd0e04da 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RewriteCountDistinctToHashRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/RewriteCountDistinctToHashRule.java
@@ -48,8 +48,8 @@ import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
  * <li>when a top-level aggregate operator also holds two-step aggregates, since local aggregation is pushed
  * only if every function in the operator is two-step. Aggregates in a nested plan are exempt: they are
  * combined by the group-by combiner instead, and that is the case the hash aggregate is meant for.</li>
- * <li>when any aggregate in the operator takes more than one argument, since the rewrite and the shared-DISTINCT
- * check above only handle single-argument aggregates.</li>
+ * <li>when any aggregate in the operator does not take exactly one argument, since the rewrite and the
+ * shared-DISTINCT check above only handle single-argument aggregates.</li>
  * </ul>
  */
 public class RewriteCountDistinctToHashRule implements IAlgebraicRewriteRule {
@@ -93,8 +93,8 @@ public class RewriteCountDistinctToHashRule implements IAlgebraicRewriteRule {
         boolean canLoseLocalPhase = !isInNestedPlan(op);
 
         // Collect the arguments already deduplicated by a distinct aggregate this rule leaves alone. Bail out
-        // if any aggregate here takes more than one argument, or if one would lose its partition-local phase,
-        // which local aggregation only keeps when every function in the operator is two-step.
+        // if any aggregate here does not take exactly one argument, or if one would lose its partition-local
+        // phase, which local aggregation only keeps when every function in the operator is two-step.
         Set<ILogicalExpression> sharedArgs = new HashSet<>();
         for (Mutable<ILogicalExpression> exprRef : aggExprs) {
             ILogicalExpression expr = exprRef.getValue();
@@ -102,7 +102,7 @@ public class RewriteCountDistinctToHashRule implements IAlgebraicRewriteRule {
                 continue;
             }
             AbstractFunctionCallExpression callExpr = (AbstractFunctionCallExpression) expr;
-            if (callExpr instanceof AggregateFunctionCallExpression && callExpr.getArguments().size() > 1) {
+            if (callExpr instanceof AggregateFunctionCallExpression && callExpr.getArguments().size() != 1) {
                 return false;
             }
             FunctionIdentifier fn = callExpr.getFunctionIdentifier();
@@ -113,7 +113,7 @@ public class RewriteCountDistinctToHashRule implements IAlgebraicRewriteRule {
                     && ((AggregateFunctionCallExpression) callExpr).isTwoStep()) {
                 return false;
             }
-            if (BuiltinFunctions.getAggregateFunctionForDistinct(fn) != null && !callExpr.getArguments().isEmpty()) {
+            if (BuiltinFunctions.getAggregateFunctionForDistinct(fn) != null) {
                 sharedArgs.add(callExpr.getArguments().get(0).getValue());
             }
         }
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.3.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.3.plan
index 2007ceb772..26cc6efb3c 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.3.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.3.plan
@@ -1,46 +1,38 @@
-distribute result [$$47]
+distribute result [$$54]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
   exchange
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$47] <- [{"count_distinct_x": $$50}] project: [$$47]
+    assign [$$54] <- [{"count_distinct_x": $$57}] project: [$$54]
     -- ASSIGN  |UNPARTITIONED|
-      aggregate [$$50] <- [agg-sql-count(1)]
+      aggregate [$$57] <- [agg-sql-count-distinct-hash($$52)]
       -- AGGREGATE  |UNPARTITIONED|
         exchange
-        -- SORT_MERGE_EXCHANGE [$$45(ASC) ]  |PARTITIONED|
-          distinct ([$$45])
-          -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
+        -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+          join (true)
+          -- NESTED_LOOP  |PARTITIONED|
             exchange
             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              order (ASC, $$45)
-              -- STABLE_SORT [$$45(ASC)]  |PARTITIONED|
+              assign [$$52] <- [$$x.getField(1)] project: [$$52]
+              -- ASSIGN  |PARTITIONED|
+                project ([$$x])
+                -- STREAM_PROJECT  |PARTITIONED|
+                  exchange
+                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                    data-scan []<-[$$55, $$x] <- test.d1
+                    -- DATASOURCE_SCAN  |PARTITIONED|
+                      exchange
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        empty-tuple-source
+                        -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+            exchange
+            -- BROADCAST_EXCHANGE  |PARTITIONED|
+              project ([])
+              -- STREAM_PROJECT  |PARTITIONED|
                 exchange
-                -- HASH_PARTITION_EXCHANGE [$$45]  |PARTITIONED|
-                  join (true)
-                  -- NESTED_LOOP  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  data-scan []<-[$$56, $$y] <- test.d2
+                  -- DATASOURCE_SCAN  |PARTITIONED|
                     exchange
                     -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                      assign [$$45] <- [$$x.getField(1)] project: [$$45]
-                      -- ASSIGN  |PARTITIONED|
-                        project ([$$x])
-                        -- STREAM_PROJECT  |PARTITIONED|
-                          exchange
-                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            data-scan []<-[$$48, $$x] <- test.d1
-                            -- DATASOURCE_SCAN  |PARTITIONED|
-                              exchange
-                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                empty-tuple-source
-                                -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
-                    exchange
-                    -- BROADCAST_EXCHANGE  |PARTITIONED|
-                      project ([])
-                      -- STREAM_PROJECT  |PARTITIONED|
-                        exchange
-                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                          data-scan []<-[$$49, $$y] <- test.d2
-                          -- DATASOURCE_SCAN  |PARTITIONED|
-                            exchange
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              empty-tuple-source
-                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                      empty-tuple-source
+                      -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
index 7ddb43e46e..525f016f0f 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
@@ -1,22 +1,16 @@
-distribute result [$$70]
+distribute result [$$81]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
   exchange
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$70] <- [{"g": $$g, "count_distinct_x": $$73}] project: [$$70]
+    assign [$$81] <- [{"g": $$g, "count_distinct_x": $$84}] project: [$$81]
     -- ASSIGN  |PARTITIONED|
       exchange
       -- SORT_MERGE_EXCHANGE [$$g(ASC) ]  |PARTITIONED|
         group by ([$$g := $$g]) decor ([]) {
-                  aggregate [$$73] <- [agg-sql-count($$68)]
+                  aggregate [$$84] <- [agg-sql-count-distinct-hash($$79)]
                   -- AGGREGATE  |LOCAL|
-                    distinct ([$$68])
-                    -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                      order (ASC, $$68)
-                      -- MICRO_STABLE_SORT [$$68(ASC)]  |LOCAL|
-                        project ([$$68])
-                        -- STREAM_PROJECT  |LOCAL|
-                          nested tuple source
-                          -- NESTED_TUPLE_SOURCE  |LOCAL|
+                    nested tuple source
+                    -- NESTED_TUPLE_SOURCE  |LOCAL|
                }
         -- PRE_CLUSTERED_GROUP_BY[$$g]  |PARTITIONED|
           exchange
@@ -33,13 +27,13 @@ distribute result [$$70]
                     -- NESTED_LOOP  |PARTITIONED|
                       exchange
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        assign [$$68] <- [$$x.getField(1)] project: [$$68]
+                        assign [$$79] <- [$$x.getField(1)] project: [$$79]
                         -- ASSIGN  |PARTITIONED|
                           project ([$$x])
                           -- STREAM_PROJECT  |PARTITIONED|
                             exchange
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              data-scan []<-[$$71, $$x] <- test.d1
+                              data-scan []<-[$$82, $$x] <- test.d1
                               -- DATASOURCE_SCAN  |PARTITIONED|
                                 exchange
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -51,7 +45,7 @@ distribute result [$$70]
                         -- STREAM_PROJECT  |PARTITIONED|
                           exchange
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            data-scan []<-[$$72, $$y] <- test.d2
+                            data-scan []<-[$$83, $$y] <- test.d2
                             -- DATASOURCE_SCAN  |PARTITIONED|
                               exchange
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/cbo-join/computed-join-predicate.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/cbo-join/computed-join-predicate.plan
index d8c9398409..4534cb2f99 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/cbo-join/computed-join-predicate.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/cbo-join/computed-join-predicate.plan
@@ -11,35 +11,11 @@ distribute result [$$188]
           exchange
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$r_name := $$189; $$su_nationkey := $$192]) decor ([]) {
-                      aggregate [$$200] <- [agg-sql-sum($$175)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      aggregate [$$200, $$201, $$202] <- [agg-sql-sum($$175), agg-sql-count-distinct-hash($$191), agg-sql-count-distinct-hash($$186)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
                         nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
                    }
-                   {
-                      aggregate [$$201] <- [agg-sql-count($$191)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- AGGREGATE  |LOCAL|
-                        distinct ([$$191]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$191) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                          -- MICRO_STABLE_SORT [$$191(ASC)]  |LOCAL|
-                            project ([$$191]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- STREAM_PROJECT  |LOCAL|
-                              nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   }
-                   {
-                      aggregate [$$202] <- [agg-sql-count($$186)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- AGGREGATE  |LOCAL|
-                        distinct ([$$186]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$186) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                          -- MICRO_STABLE_SORT [$$186(ASC)]  |LOCAL|
-                            project ([$$186]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- STREAM_PROJECT  |LOCAL|
-                              nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   }
             -- PRE_CLUSTERED_GROUP_BY[$$189, $$192]  |PARTITIONED|
               exchange
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/ch2/ch2_q16.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/ch2/ch2_q16.plan
index 8a2ed67a55..8121dc8c4a 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/ch2/ch2_q16.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/ch2/ch2_q16.plan
@@ -11,18 +11,10 @@ distribute result [$$149]
           exchange
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$i_name := $$150; $#1 := $$151; $$i_price := $$152]) decor ([]) {
-                      aggregate [$$160] <- [agg-sql-count($$171)]
+                      aggregate [$$160] <- [agg-sql-count-distinct-hash(numeric-mod(numeric-multiply($$164, $$165), 10000))]
                       -- AGGREGATE  |LOCAL|
-                        distinct ([$$171])
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$171)
-                          -- MICRO_STABLE_SORT [$$171(ASC)]  |LOCAL|
-                            assign [$$171] <- [numeric-mod(numeric-multiply($$164, $$165), 10000)] project: [$$171]
-                            -- ASSIGN  |LOCAL|
-                              project ([$$164, $$165])
-                              -- STREAM_PROJECT  |LOCAL|
-                                nested tuple source
-                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                        nested tuple source
+                        -- NESTED_TUPLE_SOURCE  |LOCAL|
                    }
             -- PRE_CLUSTERED_GROUP_BY[$$150, $$151, $$152]  |PARTITIONED|
               exchange
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
index 8b4c22350d..525f016f0f 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/aggregate-sql-sugar/distinct_mixed/distinct_mixed.9.plan
@@ -1,22 +1,16 @@
-distribute result [$$80]
+distribute result [$$81]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
   exchange
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$80] <- [{"g": $$g, "count_distinct_x": $$83}] project: [$$80]
+    assign [$$81] <- [{"g": $$g, "count_distinct_x": $$84}] project: [$$81]
     -- ASSIGN  |PARTITIONED|
       exchange
       -- SORT_MERGE_EXCHANGE [$$g(ASC) ]  |PARTITIONED|
         group by ([$$g := $$g]) decor ([]) {
-                  aggregate [$$83] <- [agg-sql-count($$78)]
+                  aggregate [$$84] <- [agg-sql-count-distinct-hash($$79)]
                   -- AGGREGATE  |LOCAL|
-                    distinct ([$$78])
-                    -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                      order (ASC, $$78)
-                      -- MICRO_STABLE_SORT [$$78(ASC)]  |LOCAL|
-                        project ([$$78])
-                        -- STREAM_PROJECT  |LOCAL|
-                          nested tuple source
-                          -- NESTED_TUPLE_SOURCE  |LOCAL|
+                    nested tuple source
+                    -- NESTED_TUPLE_SOURCE  |LOCAL|
                }
         -- PRE_CLUSTERED_GROUP_BY[$$g]  |PARTITIONED|
           exchange
@@ -33,13 +27,13 @@ distribute result [$$80]
                     -- NESTED_LOOP  |PARTITIONED|
                       exchange
                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                        assign [$$78] <- [$$x.getField(1)] project: [$$78]
+                        assign [$$79] <- [$$x.getField(1)] project: [$$79]
                         -- ASSIGN  |PARTITIONED|
                           project ([$$x])
                           -- STREAM_PROJECT  |PARTITIONED|
                             exchange
                             -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              data-scan []<-[$$81, $$x] <- test.d1
+                              data-scan []<-[$$82, $$x] <- test.d1
                               -- DATASOURCE_SCAN  |PARTITIONED|
                                 exchange
                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -51,7 +45,7 @@ distribute result [$$80]
                         -- STREAM_PROJECT  |PARTITIONED|
                           exchange
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                            data-scan []<-[$$82, $$y] <- test.d2
+                            data-scan []<-[$$83, $$y] <- test.d2
                             -- DATASOURCE_SCAN  |PARTITIONED|
                               exchange
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/cbo-join/computed-join-predicate.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/cbo-join/computed-join-predicate.plan
index 0ec68db058..1212e73ad8 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/cbo-join/computed-join-predicate.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/cbo-join/computed-join-predicate.plan
@@ -11,34 +11,10 @@ distribute result [$$188] [cardinality: 0.0, doc-size: -5.0, op-cost: 0.0, total
           exchange [cardinality: 0.0, doc-size: -5.0, op-cost: 0.0, total-cost: 0.0]
           -- RANGE_PARTITION_EXCHANGE [$$200(DESC), $$r_name(ASC), $$su_nationkey(ASC)] RANGE_MAP:{SPLIT:1}  |PARTITIONED|
             group by ([$$r_name := $$189; $$su_nationkey := $$192]) decor ([]) {
-                      aggregate [$$200] <- [agg-sql-sum($$175)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      aggregate [$$200, $$201, $$202] <- [agg-sql-sum($$175), agg-sql-count-distinct-hash($$191), agg-sql-count-distinct-hash($$186)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
                         nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   }
-                   {
-                      aggregate [$$201] <- [agg-sql-count($$191)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- AGGREGATE  |LOCAL|
-                        distinct ([$$191]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$191) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                          -- MICRO_STABLE_SORT [$$191(ASC)]  |LOCAL|
-                            project ([$$191]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- STREAM_PROJECT  |LOCAL|
-                              nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   }
-                   {
-                      aggregate [$$202] <- [agg-sql-count($$186)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- AGGREGATE  |LOCAL|
-                        distinct ([$$186]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$186) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                          -- MICRO_STABLE_SORT [$$186(ASC)]  |LOCAL|
-                            project ([$$186]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- STREAM_PROJECT  |LOCAL|
-                              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, doc-size: -5.0, op-cost: 0.0, total-cost: 0.0]
             -- PRE_CLUSTERED_GROUP_BY[$$189, $$192]  |PARTITIONED|
               exchange [cardinality: 0.0, doc-size: -5.0, op-cost: 0.0, total-cost: 0.0]
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q16.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q16.plan
index f727f5716d..19a8d5b4d9 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q16.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/ch2/ch2_q16.plan
@@ -1,43 +1,35 @@
-distribute result [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+distribute result [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
 -- DISTRIBUTE_RESULT  |PARTITIONED|
-  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-    assign [$$149] <- [{"i_name": $$i_name, "brand": $#1, "i_price": $$i_price, "supplier_cnt": $$160}] project: [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+    assign [$$149] <- [{"i_name": $$i_name, "brand": $#1, "i_price": $$i_price, "supplier_cnt": $$160}] project: [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
     -- ASSIGN  |PARTITIONED|
-      exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+      exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
       -- SORT_MERGE_EXCHANGE [$$160(DESC) ]  |PARTITIONED|
-        order (DESC, $$160) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+        order (DESC, $$160) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
         -- STABLE_SORT [$$160(DESC)]  |PARTITIONED|
-          exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+          exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
             group by ([$$i_name := $$150; $#1 := $$151; $$i_price := $$152]) decor ([]) {
-                      aggregate [$$160] <- [agg-sql-count($$171)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                      aggregate [$$160] <- [agg-sql-count-distinct-hash(numeric-mod(numeric-multiply($$164, $$165), 10000))] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                       -- AGGREGATE  |LOCAL|
-                        distinct ([$$171]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- MICRO_PRE_SORTED_DISTINCT_BY  |LOCAL|
-                          order (ASC, $$171) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                          -- MICRO_STABLE_SORT [$$171(ASC)]  |LOCAL|
-                            assign [$$171] <- [numeric-mod(numeric-multiply($$164, $$165), 10000)] project: [$$171] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                            -- ASSIGN  |LOCAL|
-                              project ([$$164, $$165]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                              -- STREAM_PROJECT  |LOCAL|
-                                nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- NESTED_TUPLE_SOURCE  |LOCAL|
-                   } [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                        nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- NESTED_TUPLE_SOURCE  |LOCAL|
+                   } [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
             -- PRE_CLUSTERED_GROUP_BY[$$150, $$151, $$152]  |PARTITIONED|
-              exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+              exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                order (ASC, $$150) (ASC, $$151) (ASC, $$152) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                order (ASC, $$150) (ASC, $$151) (ASC, $$152) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                 -- STABLE_SORT [$$150(ASC), $$151(ASC), $$152(ASC)]  |PARTITIONED|
-                  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                   -- HASH_PARTITION_EXCHANGE [$$150, $$151, $$152]  |PARTITIONED|
-                    assign [$$151] <- [substring1($$153, 1, 3)] project: [$$164, $$165, $$150, $$151, $$152] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                    assign [$$151] <- [substring1($$153, 1, 3)] project: [$$164, $$165, $$150, $$151, $$152] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                     -- ASSIGN  |PARTITIONED|
-                      select ($$132) project: [$$150, $$152, $$153, $$165, $$164] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                      select ($$132) project: [$$150, $$152, $$153, $$165, $$164] [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                       -- STREAM_SELECT  |PARTITIONED|
-                        project ([$$132, $$150, $$152, $$153, $$165, $$164]) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                        project ([$$132, $$150, $$152, $$153, $$165, $$164]) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                         -- STREAM_PROJECT  |PARTITIONED|
-                          exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                          exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
                             group by ([$$167 := $$154; $$168 := $$155]) decor ([$$150; $$152; $$153; $$165 := $$159; $$164 := $$162]) {
                                       aggregate [$$132] <- [empty-stream()] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
@@ -48,35 +40,35 @@ distribute result [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op
                                           -- STREAM_PROJECT  |LOCAL|
                                             nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                             -- NESTED_TUPLE_SOURCE  |LOCAL|
-                                   } [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                                   } [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                             -- PRE_CLUSTERED_GROUP_BY[$$154, $$155]  |PARTITIONED|
-                              exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                              exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                order (ASC, $$154) (ASC, $$155) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                                order (ASC, $$154) (ASC, $$155) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                                 -- STABLE_SORT [$$154(ASC), $$155(ASC)]  |PARTITIONED|
-                                  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                                  exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                    project ([$$150, $$152, $$153, $$166, $$154, $$155, $$159, $$162]) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                                    project ([$$150, $$152, $$153, $$166, $$154, $$155, $$159, $$162]) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                                     -- STREAM_PROJECT  |PARTITIONED|
-                                      exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 1.500015E12]
+                                      exchange [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 0.0, total-cost: 6.2500500004499976E16]
                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                        join (eq($$158, $$159)) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 5.00004E11, total-cost: 1.500015E12]
+                                        join (eq($$158, $$159)) [cardinality: 9.223372036854776E16, doc-size: -3.0, op-cost: 6.2500125001E16, total-cost: 6.2500500004499976E16]
                                         -- HYBRID_HASH_JOIN [$$159][$$158]  |PARTITIONED|
-                                          exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                          exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                            project ([$$166, $$154, $$159, $$162]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                            project ([$$166, $$154, $$159, $$162]) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                             -- STREAM_PROJECT  |PARTITIONED|
-                                              exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                              exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                               -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                left outer join (not(if-missing-or-null(neq(numeric-mod(numeric-multiply($$162, $$159), 10000), $$126), false))) [cardinality: 5.0E11, doc-size: -2.0, op-cost: 1.0E12, total-cost: 1.000006E12]
+                                                left outer join (not(if-missing-or-null(neq(numeric-mod(numeric-multiply($$162, $$159), 10000), $$126), false))) [cardinality: 5.0E11, doc-size: -2.0, op-cost: 3.75E11, total-cost: 3.7500199998474E11]
                                                 -- NESTED_LOOP  |PARTITIONED|
-                                                  exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                  exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                   -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                    assign [$$159, $$162] <- [$$s.getField("s_i_id"), $$s.getField("s_w_id")] project: [$$154, $$159, $$162] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                    assign [$$159, $$162] <- [$$s.getField("s_i_id"), $$s.getField("s_w_id")] project: [$$154, $$159, $$162] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                     -- ASSIGN  |PARTITIONED|
-                                                      exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                      exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                       -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                        data-scan []<-[$$154, $$s] <- test.stock [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                        data-scan []<-[$$154, $$s] <- test.stock [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                         -- DATASOURCE_SCAN  |PARTITIONED|
                                                           exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                           -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
@@ -86,7 +78,7 @@ distribute result [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op
                                                   -- BROADCAST_EXCHANGE  |PARTITIONED|
                                                     assign [$$166] <- [true] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                     -- ASSIGN  |PARTITIONED|
-                                                      select (like($$su.getField("su_comment"), "%Customer%Complaints%")) project: [$$126] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                      select (like($$su.getField("su_comment"), "%Customer%Complaints%")) project: [$$126] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                       -- STREAM_SELECT  |PARTITIONED|
                                                         assign [$$126] <- [$$su.getField("su_suppkey")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
                                                         -- ASSIGN  |PARTITIONED|
@@ -94,21 +86,21 @@ distribute result [$$149] [cardinality: 9.223372036854776E16, doc-size: -3.0, op
                                                           -- 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 []<-[$$156, $$su] <- test.supplier [cardinality: 1000000.0, doc-size: -1.0, op-cost: 1000000.0, total-cost: 1000000.0]
+                                                              data-scan []<-[$$156, $$su] <- test.supplier [cardinality: 1000000.0, doc-size: -1.0, op-cost: 499992.37, total-cost: 499992.37]
                                                               -- 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]
+                                          exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                           -- BROADCAST_EXCHANGE  |PARTITIONED|
-                                            select (not(and(ge($$153, "zz"), lt($$153, "z{")))) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                            select (not(and(ge($$153, "zz"), lt($$153, "z{")))) [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                             -- STREAM_SELECT  |PARTITIONED|
-                                              assign [$$152, $$150, $$153, $$158] <- [$$i.getField("i_price"), $$i.getField("i_name"), $$i.getField("i_data"), $$i.getField("i_id")] project: [$$155, $$152, $$150, $$153, $$158] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                              assign [$$152, $$150, $$153, $$158] <- [$$i.getField("i_price"), $$i.getField("i_name"), $$i.getField("i_data"), $$i.getField("i_id")] project: [$$155, $$152, $$150, $$153, $$158] [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                               -- ASSIGN  |PARTITIONED|
-                                                exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                exchange [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                 -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                                                  data-scan []<-[$$155, $$i] <- test.item [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 1000000.0]
+                                                  data-scan []<-[$$155, $$i] <- test.item [cardinality: 1000000.0, doc-size: -1.0, op-cost: 0.0, total-cost: 499992.37]
                                                   -- DATASOURCE_SCAN  |PARTITIONED|
                                                     exchange [cardinality: 0.0, doc-size: 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/api/cluster_state_1/cluster_state_1.1.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
index b591bf545d..3d02a9d0a6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
@@ -48,7 +48,7 @@
     "cloud.storage.scheme" : "",
     "cloud.storage.sweep.threshold.percentage" : 0.9,
     "cloud.write.buffer.size" : 8388608,
-    "compiler.aggregate.distinct.hash" : false,
+    "compiler.aggregate.distinct.hash" : true,
     "compiler.aggregate.distinct.hash.memory" : 33554432,
     "compiler\.arrayindex" : true,
     "compiler.batch.lookup" : true,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
index 388761de14..2d434d8025 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
@@ -48,7 +48,7 @@
     "cloud.storage.scheme" : "",
     "cloud.storage.sweep.threshold.percentage" : 0.9,
     "cloud.write.buffer.size" : 8388608,
-    "compiler.aggregate.distinct.hash" : false,
+    "compiler.aggregate.distinct.hash" : true,
     "compiler.aggregate.distinct.hash.memory" : 33554432,
     "compiler\.arrayindex" : true,
     "compiler.batch.lookup" : true,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
index 58458203ff..b258b0496b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
@@ -48,7 +48,7 @@
     "cloud.storage.scheme" : "",
     "cloud.storage.sweep.threshold.percentage" : 0.9,
     "cloud.write.buffer.size" : 8388608,
-    "compiler.aggregate.distinct.hash" : false,
+    "compiler.aggregate.distinct.hash" : true,
     "compiler.aggregate.distinct.hash.memory" : 33554432,
     "compiler\.arrayindex" : true,
     "compiler.batch.lookup" : true,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.020.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.020.plan
index f9e72f41a8..64b781e46e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.020.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.020.plan
@@ -1,47 +1,39 @@
-distribute result [$$66] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
   exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$66] <- [{"count": $$69}] project: [$$66] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- ASSIGN  |UNPARTITIONED|
-      aggregate [$$69] <- [agg-sql-count(1)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+      aggregate [$$78] <- [agg-sql-count-distinct-hash($$73)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- AGGREGATE  |UNPARTITIONED|
         exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-        -- SORT_MERGE_EXCHANGE [$$64(ASC) ]  |PARTITIONED|
-          distinct ([$$64]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-          -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-            exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              order (ASC, $$64) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-              -- STABLE_SORT [$$64(ASC)]  |PARTITIONED|
-                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                -- HASH_PARTITION_EXCHANGE [$$64]  |PARTITIONED|
-                  select (ge($$68, 3)) project: [$$64] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                  -- STREAM_SELECT  |PARTITIONED|
-                    project ([$$64, $$68]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                    -- STREAM_PROJECT  |PARTITIONED|
-                      subplan {
-                                aggregate [$$68] <- [agg-sql-sum($$52)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- AGGREGATE  |LOCAL|
-                                  assign [$$52] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                  -- ASSIGN  |LOCAL|
-                                    unnest $$i <- scan-collection($$70) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                    -- UNNEST  |LOCAL|
-                                      project ([$$70]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                      -- STREAM_PROJECT  |LOCAL|
-                                        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, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- SUBPLAN  |PARTITIONED|
-                        assign [$$64, $$70] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$64, $$70] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- ASSIGN  |PARTITIONED|
-                          project ([$$t]) [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 []<-[$$67, $$t] <- test.ColumnDataset [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.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|
+        -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+          select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- STREAM_SELECT  |PARTITIONED|
+            project ([$$73, $$77]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- STREAM_PROJECT  |PARTITIONED|
+              subplan {
+                        aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- AGGREGATE  |LOCAL|
+                          assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- ASSIGN  |LOCAL|
+                            unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- UNNEST  |LOCAL|
+                              project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_PROJECT  |LOCAL|
+                                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, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- SUBPLAN  |PARTITIONED|
+                assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ASSIGN  |PARTITIONED|
+                  project ([$$t]) [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 []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.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/column/pushdown/other-pushdowns/other-pushdowns.021.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.021.plan
index f9e72f41a8..64b781e46e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.021.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/column/pushdown/other-pushdowns/other-pushdowns.021.plan
@@ -1,47 +1,39 @@
-distribute result [$$66] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
   exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$66] <- [{"count": $$69}] project: [$$66] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
     -- ASSIGN  |UNPARTITIONED|
-      aggregate [$$69] <- [agg-sql-count(1)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+      aggregate [$$78] <- [agg-sql-count-distinct-hash($$73)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
       -- AGGREGATE  |UNPARTITIONED|
         exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-        -- SORT_MERGE_EXCHANGE [$$64(ASC) ]  |PARTITIONED|
-          distinct ([$$64]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-          -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-            exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              order (ASC, $$64) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-              -- STABLE_SORT [$$64(ASC)]  |PARTITIONED|
-                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                -- HASH_PARTITION_EXCHANGE [$$64]  |PARTITIONED|
-                  select (ge($$68, 3)) project: [$$64] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                  -- STREAM_SELECT  |PARTITIONED|
-                    project ([$$64, $$68]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                    -- STREAM_PROJECT  |PARTITIONED|
-                      subplan {
-                                aggregate [$$68] <- [agg-sql-sum($$52)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- AGGREGATE  |LOCAL|
-                                  assign [$$52] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                  -- ASSIGN  |LOCAL|
-                                    unnest $$i <- scan-collection($$70) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                    -- UNNEST  |LOCAL|
-                                      project ([$$70]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                      -- STREAM_PROJECT  |LOCAL|
-                                        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, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                      -- SUBPLAN  |PARTITIONED|
-                        assign [$$64, $$70] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$64, $$70] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                        -- ASSIGN  |PARTITIONED|
-                          project ([$$t]) [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 []<-[$$67, $$t] <- test.ColumnDataset [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.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|
+        -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+          select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+          -- STREAM_SELECT  |PARTITIONED|
+            project ([$$73, $$77]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+            -- STREAM_PROJECT  |PARTITIONED|
+              subplan {
+                        aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- AGGREGATE  |LOCAL|
+                          assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- ASSIGN  |LOCAL|
+                            unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- UNNEST  |LOCAL|
+                              project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_PROJECT  |LOCAL|
+                                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, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+              -- SUBPLAN  |PARTITIONED|
+                assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                -- ASSIGN  |PARTITIONED|
+                  project ([$$t]) [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 []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.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/column/pushdown/other-pushdowns/other-pushdowns.020.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.020.plan
index 7726f3ae99..1ca0a9dd4b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.020.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.020.plan
@@ -1,47 +1,39 @@
-distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+  exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
     -- ASSIGN  |UNPARTITIONED|
-      aggregate [$$78] <- [agg-sql-count(1)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+      aggregate [$$78] <- [agg-sql-count-distinct-hash($$73)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
       -- AGGREGATE  |UNPARTITIONED|
-        exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-        -- SORT_MERGE_EXCHANGE [$$73(ASC) ]  |PARTITIONED|
-          distinct ([$$73]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-          -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-            exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              order (ASC, $$73) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-              -- STABLE_SORT [$$73(ASC)]  |PARTITIONED|
-                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                -- HASH_PARTITION_EXCHANGE [$$73]  |PARTITIONED|
-                  select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                  -- STREAM_SELECT  |PARTITIONED|
-                    project ([$$73, $$77]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                    -- STREAM_PROJECT  |PARTITIONED|
-                      subplan {
-                                aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- AGGREGATE  |LOCAL|
-                                  assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                  -- ASSIGN  |LOCAL|
-                                    unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                    -- UNNEST  |LOCAL|
-                                      project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                      -- STREAM_PROJECT  |LOCAL|
-                                        nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                        -- NESTED_TUPLE_SOURCE  |LOCAL|
-                             } [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                      -- SUBPLAN  |PARTITIONED|
-                        assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                        -- ASSIGN  |PARTITIONED|
-                          project ([$$t]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                          -- STREAM_PROJECT  |PARTITIONED|
-                            exchange [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              data-scan []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.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.5]
+        -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+          select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+          -- STREAM_SELECT  |PARTITIONED|
+            project ([$$73, $$77]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+            -- STREAM_PROJECT  |PARTITIONED|
+              subplan {
+                        aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- AGGREGATE  |LOCAL|
+                          assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- ASSIGN  |LOCAL|
+                            unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- UNNEST  |LOCAL|
+                              project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_PROJECT  |LOCAL|
+                                nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                     } [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+              -- SUBPLAN  |PARTITIONED|
+                assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                -- ASSIGN  |PARTITIONED|
+                  project ([$$t]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      data-scan []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                      -- 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/column/pushdown/other-pushdowns/other-pushdowns.021.plan b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.021.plan
index 7726f3ae99..1ca0a9dd4b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.021.plan
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/column/pushdown/other-pushdowns/other-pushdowns.021.plan
@@ -1,47 +1,39 @@
-distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+distribute result [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
 -- DISTRIBUTE_RESULT  |UNPARTITIONED|
-  exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+  exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
   -- ONE_TO_ONE_EXCHANGE  |UNPARTITIONED|
-    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+    assign [$$75] <- [{"count": $$78}] project: [$$75] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
     -- ASSIGN  |UNPARTITIONED|
-      aggregate [$$78] <- [agg-sql-count(1)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
+      aggregate [$$78] <- [agg-sql-count-distinct-hash($$73)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
       -- AGGREGATE  |UNPARTITIONED|
-        exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-        -- SORT_MERGE_EXCHANGE [$$73(ASC) ]  |PARTITIONED|
-          distinct ([$$73]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-          -- PRE_SORTED_DISTINCT_BY  |PARTITIONED|
-            exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-              order (ASC, $$73) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-              -- STABLE_SORT [$$73(ASC)]  |PARTITIONED|
-                exchange [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                -- HASH_PARTITION_EXCHANGE [$$73]  |PARTITIONED|
-                  select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                  -- STREAM_SELECT  |PARTITIONED|
-                    project ([$$73, $$77]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                    -- STREAM_PROJECT  |PARTITIONED|
-                      subplan {
-                                aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                -- AGGREGATE  |LOCAL|
-                                  assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                  -- ASSIGN  |LOCAL|
-                                    unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                    -- UNNEST  |LOCAL|
-                                      project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                      -- STREAM_PROJECT  |LOCAL|
-                                        nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
-                                        -- NESTED_TUPLE_SOURCE  |LOCAL|
-                             } [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                      -- SUBPLAN  |PARTITIONED|
-                        assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                        -- ASSIGN  |PARTITIONED|
-                          project ([$$t]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                          -- STREAM_PROJECT  |PARTITIONED|
-                            exchange [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.0]
-                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
-                              data-scan []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 2.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.5]
+        -- RANDOM_MERGE_EXCHANGE  |PARTITIONED|
+          select (ge($$77, 3)) project: [$$73] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+          -- STREAM_SELECT  |PARTITIONED|
+            project ([$$73, $$77]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+            -- STREAM_PROJECT  |PARTITIONED|
+              subplan {
+                        aggregate [$$77] <- [agg-sql-sum($$61)] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                        -- AGGREGATE  |LOCAL|
+                          assign [$$61] <- [$$i.getField("count")] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                          -- ASSIGN  |LOCAL|
+                            unnest $$i <- scan-collection($$79) project: [$$i] [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                            -- UNNEST  |LOCAL|
+                              project ([$$79]) [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                              -- STREAM_PROJECT  |LOCAL|
+                                nested tuple source [cardinality: 0.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.0]
+                                -- NESTED_TUPLE_SOURCE  |LOCAL|
+                     } [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+              -- SUBPLAN  |PARTITIONED|
+                assign [$$73, $$79] <- [to-object-var-str($$t).getField(0), $$t.getField("a1")] project: [$$73, $$79] [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                -- ASSIGN  |PARTITIONED|
+                  project ([$$t]) [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    exchange [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      data-scan []<-[$$76, $$t] <- test.ColumnDataset [cardinality: 2.0, doc-size: 0.0, op-cost: 0.0, total-cost: 0.5]
+                      -- 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/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
index 628105f7ef..862801c749 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/config/AlgebricksConfig.java
@@ -41,7 +41,7 @@ public class AlgebricksConfig {
     public static final int CBO_MAX_JOINS_UPPER_BOUND = 19;
     public static final boolean FORCE_JOIN_ORDER_DEFAULT = false;
     public static final boolean REWRITE_DISJUNCTION_DEFAULT = false;
-    public static final boolean AGGREGATE_DISTINCT_HASH_DEFAULT = false;
+    public static final boolean AGGREGATE_DISTINCT_HASH_DEFAULT = true;
     public static final String QUERY_PLAN_SHAPE_ZIGZAG = "zigzag";
     public static final String QUERY_PLAN_SHAPE_LEFTDEEP = "leftdeep";
     public static final String QUERY_PLAN_SHAPE_RIGHTDEEP = "rightdeep";