(1 row)
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
select count(*) from (select h from (select * from testhstore union all select * from testhstore) hs group by h) hs2;
count
-------
(1 row)
-set enable_sort = true;
+set enable_groupagg = true;
-- btree
drop index hidx;
create index hidx on testhstore using btree (h);
set enable_hashagg = false;
select count(*) from (select h from (select * from testhstore union all select * from testhstore) hs group by h) hs2;
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
select count(*) from (select h from (select * from testhstore union all select * from testhstore) hs group by h) hs2;
select distinct * from (values (hstore '' || ''),('')) v(h);
-set enable_sort = true;
+set enable_groupagg = true;
-- btree
drop index hidx;
reset enable_bitmapscan;
-- test hash aggregate
set enable_hashagg=on;
-set enable_sort=off;
+set enable_groupagg=off;
EXPLAIN (COSTS OFF)
SELECT count(*) FROM (
SELECT t FROM (SELECT * FROM ltreetest UNION ALL SELECT * FROM ltreetest) t1 GROUP BY t
(1 row)
reset enable_hashagg;
-reset enable_sort;
+reset enable_groupagg;
drop index tstidx;
-- test gist index
create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=0));
-- test hash aggregate
set enable_hashagg=on;
-set enable_sort=off;
+set enable_groupagg=off;
EXPLAIN (COSTS OFF)
SELECT count(*) FROM (
) t2;
reset enable_hashagg;
-reset enable_sort;
+reset enable_groupagg;
drop index tstidx;
</listitem>
</varlistentry>
+ <varlistentry id="guc-enable-groupagg" xreflabel="enable_groupagg">
+ <term><varname>enable_groupagg</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>enable_groupagg</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Enables or disables the query planner's use of sort-based grouping
+ and aggregation plan types. The default is <literal>on</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-enable-hashagg" xreflabel="enable_hashagg">
<term><varname>enable_hashagg</varname> (<type>boolean</type>)
<indexterm>
bool enable_sort = true;
bool enable_incremental_sort = true;
bool enable_hashagg = true;
+bool enable_groupagg = true;
bool enable_nestloop = true;
bool enable_material = true;
bool enable_memoize = true;
/* we aren't grouping */
total_cost = startup_cost + cpu_tuple_cost;
output_tuples = 1;
+
+ /* AGG_PLAIN neither hashes nor sorts, so neither switch disables it */
}
else if (aggstrategy == AGG_SORTED || aggstrategy == AGG_MIXED)
{
/* Here we are able to deliver output on-the-fly */
startup_cost = input_startup_cost;
total_cost = input_total_cost;
- if (aggstrategy == AGG_MIXED && !enable_hashagg)
- ++disabled_nodes;
/* calcs phrased this way to match HASHED case, see note above */
total_cost += aggcosts->transCost.startup;
total_cost += aggcosts->transCost.per_tuple * input_tuples;
total_cost += aggcosts->finalCost.per_tuple * numGroups;
total_cost += cpu_tuple_cost * numGroups;
output_tuples = numGroups;
+
+ /*
+ * AGG_MIXED hashes at least one grouping set, so it is disabled when
+ * enable_hashagg is off. Any sorted grouping it also performs is
+ * costed separately, since create_groupingsets_path() calls
+ * cost_agg() once per rollup and the non-hashed rollups come through
+ * as AGG_SORTED.
+ *
+ * AGG_SORTED is disabled when enable_groupagg is off, but only when
+ * there are grouping columns. The empty grouping set arrives with
+ * numGroupCols == 0 and is computed like AGG_PLAIN, with no hashing
+ * or sorting, so it isn't disabled.
+ */
+ if (aggstrategy == AGG_MIXED)
+ {
+ if (!enable_hashagg)
+ ++disabled_nodes;
+ }
+ else if (numGroupCols > 0 && !enable_groupagg) /* AGG_SORTED */
+ ++disabled_nodes;
}
else
{
/* must be AGG_HASHED */
startup_cost = input_total_cost;
- if (!enable_hashagg)
- ++disabled_nodes;
startup_cost += aggcosts->transCost.startup;
startup_cost += aggcosts->transCost.per_tuple * input_tuples;
/* cost of computing hash value */
/* cost of retrieving from hash table */
total_cost += cpu_tuple_cost * numGroups;
output_tuples = numGroups;
+
+ /* AGG_HASHED is disabled when enable_hashagg is off */
+ if (!enable_hashagg)
+ ++disabled_nodes;
}
/*
}
path->rows = output_tuples;
- path->disabled_nodes = input_disabled_nodes;
+ path->disabled_nodes = input_disabled_nodes + (enable_groupagg ? 0 : 1);
path->startup_cost = startup_cost;
path->total_cost = total_cost;
}
cpu_operator_cost * subpath->rows * numCols;
pathnode->path.rows = numGroups;
+ /*
+ * Mark the path as disabled if enable_groupagg is off. While this isn't
+ * a grouping Agg node, it is the sort-based way of removing duplicates
+ * and so is the natural counterpart to the AGG_HASHED path that
+ * enable_hashagg controls; it seems close enough to justify letting that
+ * switch control it.
+ */
+ if (!enable_groupagg)
+ pathnode->path.disabled_nodes++;
+
return pathnode;
}
* qual-checking or projection.
*/
pathnode->path.total_cost += cpu_operator_cost * outputRows;
+
+ /*
+ * Mark the path as disabled if enable_groupagg is off. While this
+ * isn't a grouping Agg node, it is the sort-based implementation and
+ * so is the natural counterpart to the SETOP_HASHED path that
+ * enable_hashagg controls; it seems close enough to justify letting
+ * that switch control it.
+ */
+ if (!enable_groupagg)
+ pathnode->path.disabled_nodes++;
}
else
{
boot_val => 'true',
},
+{ name => 'enable_groupagg', type => 'bool', context => 'PGC_USERSET', group => 'QUERY_TUNING_METHOD',
+ short_desc => 'Enables the planner\'s use of sort-based grouping and aggregation plans.',
+ flags => 'GUC_EXPLAIN',
+ variable => 'enable_groupagg',
+ boot_val => 'true',
+},
+
{ name => 'enable_hashagg', type => 'bool', context => 'PGC_USERSET', group => 'QUERY_TUNING_METHOD',
short_desc => 'Enables the planner\'s use of hashed aggregation plans.',
flags => 'GUC_EXPLAIN',
#enable_async_append = on
#enable_bitmapscan = on
#enable_gathermerge = on
+#enable_groupagg = on
#enable_hashagg = on
#enable_hashjoin = on
#enable_incremental_sort = on
extern PGDLLIMPORT bool enable_sort;
extern PGDLLIMPORT bool enable_incremental_sort;
extern PGDLLIMPORT bool enable_hashagg;
+extern PGDLLIMPORT bool enable_groupagg;
extern PGDLLIMPORT bool enable_nestloop;
extern PGDLLIMPORT bool enable_material;
extern PGDLLIMPORT bool enable_memoize;
INSERT INTO hashagg_ij SELECT g FROM generate_series(1,5100) g;
SET max_parallel_workers=0;
SET max_parallel_workers_per_gather=0;
-SET enable_sort=FALSE;
+SET enable_groupagg=FALSE;
SET work_mem='4MB';
SELECT COUNT(*) FROM (SELECT DISTINCT x FROM hashagg_ij) s;
NOTICE: notice triggered for injection point hash-aggregate-spill-1000
SET max_parallel_workers=0;
SET max_parallel_workers_per_gather=0;
-SET enable_sort=FALSE;
+SET enable_groupagg=FALSE;
SET work_mem='4MB';
SELECT COUNT(*) FROM (SELECT DISTINCT x FROM hashagg_ij) s;
drop cascades to table minmaxtest3
-- DISTINCT can also trigger wrong answers with hash aggregation (bug #18465)
begin;
-set local enable_sort = off;
+set local enable_groupagg = off;
explain (costs off)
select f1, (select distinct min(t1.f1) from int4_tbl t1 where t1.f1 = t0.f1)
from int4_tbl t0;
--
-- Hash Aggregation Spill tests
--
-set enable_sort=false;
+set enable_groupagg=false;
set work_mem='64kB';
select unique1, count(*), sum(twothousand) from tenk1
group by unique1
(48 rows)
set work_mem to default;
-set enable_sort to default;
+set enable_groupagg to default;
--
-- Compare results between plans using sorting and plans using hash
-- aggregation. Force spilling in both cases by setting work_mem low.
from agg_data_2k group by g/2;
-- Produce results with hash aggregation
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
set jit_above_cost = 0;
explain (costs off)
select g%10000 as c1, sum(g::numeric) as c2, count(*) as c3
create table agg_hash_4 as
select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3
from agg_data_2k group by g/2;
-set enable_sort = true;
+set enable_groupagg = true;
set work_mem to default;
-- Compare group aggregation results to hash aggregation results
(select * from agg_hash_1 except select * from agg_group_1)
update pg_class set reltuples = 10 where relname='bug_16784';
insert into bug_16784 select g/10, g from generate_series(1,40) g;
set work_mem='64kB';
-set enable_sort = false;
+set enable_groupagg = false;
select * from
(values (1),(2)) v(a),
lateral (select a, i, j, count(*) from
update pg_class set reltuples = 10 where relname='gs_data_1';
set work_mem='64kB';
-- Produce results with sorting.
-set enable_sort = true;
+set enable_groupagg = true;
set enable_hashagg = false;
set jit_above_cost = 0;
explain (costs off)
from gs_data_1 group by cube (g1000, g100,g10);
-- Produce results with hash aggregation.
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
explain (costs off)
select g100, g10, sum(g::numeric), count(*), max(g::text)
from gs_data_1 group by cube (g1000, g100,g10);
create table gs_hash_1 as
select g100, g10, sum(g::numeric), count(*), max(g::text)
from gs_data_1 group by cube (g1000, g100,g10);
-set enable_sort = true;
+set enable_groupagg = true;
set work_mem to default;
set hash_mem_multiplier to default;
-- Compare results
(1 row)
SET enable_hashagg = on;
-SET enable_sort = off;
+SET enable_groupagg = off;
SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
count
-------
{}
(1 row)
-SET enable_sort = on;
+SET enable_groupagg = on;
RESET enable_hashagg;
-RESET enable_sort;
+RESET enable_groupagg;
DROP INDEX jidx;
DROP INDEX jidx_array;
-- btree
--
-- Check behavior when subtype lacks a hash function
--
-set enable_sort = off; -- try to make it pick a hash setop implementation
+set enable_groupagg = off; -- try to make it pick a hash setop implementation
select '{(01,10)}'::varbitmultirange except select '{(10,11)}'::varbitmultirange;
varbitmultirange
------------------
{(01,10)}
(1 row)
-reset enable_sort;
+reset enable_groupagg;
--
-- OUT/INOUT/TABLE functions
--
-- Check behavior when subtype lacks a hash function
--
create type varbitrange as range (subtype = varbit);
-set enable_sort = off; -- try to make it pick a hash setop implementation
+set enable_groupagg = off; -- try to make it pick a hash setop implementation
select '(01,10)'::varbitrange except select '(10,11)'::varbitrange;
varbitrange
-------------
(01,10)
(1 row)
-reset enable_sort;
+reset enable_groupagg;
--
-- OUT/INOUT/TABLE functions
--
RESET enable_seqscan;
SET enable_hashagg=TRUE;
-- Produce results with hash aggregation.
-SET enable_sort=FALSE;
+SET enable_groupagg=FALSE;
SET jit_above_cost=0;
EXPLAIN (costs off)
SELECT DISTINCT g%1000 FROM generate_series(0,9999) g;
SET jit_above_cost TO DEFAULT;
CREATE TABLE distinct_hash_2 AS
SELECT DISTINCT (g%1000)::text FROM generate_series(0,9999) g;
-SET enable_sort=TRUE;
+SET enable_groupagg=TRUE;
SET work_mem TO DEFAULT;
-- Compare results
(SELECT * FROM distinct_hash_1 EXCEPT SELECT * FROM distinct_group_1)
-- Test rescan of a hashed SetOp node
--
begin;
-set local enable_sort = off;
+set local enable_groupagg = off;
explain (costs off)
select count(*) from
onek o cross join lateral (
enable_eager_aggregate | on
enable_gathermerge | on
enable_group_by_reordering | on
+ enable_groupagg | on
enable_hashagg | on
enable_hashjoin | on
enable_incremental_sort | on
enable_seqscan | on
enable_sort | on
enable_tidscan | on
-(25 rows)
+(26 rows)
-- There are always wait event descriptions for various types. InjectionPoint
-- may be present or absent, depending on history since last postmaster start.
(1 row)
-- this query will prefer a sorted setop unless we force it.
-set enable_indexscan to off;
+set enable_groupagg to off;
explain (costs off)
select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
- QUERY PLAN
----------------------------------
+ QUERY PLAN
+------------------------------------------------------------
HashSetOp Except
- -> Seq Scan on tenk1
- -> Seq Scan on tenk1 tenk1_1
+ -> Index Only Scan using tenk1_unique1 on tenk1
+ -> Index Only Scan using tenk1_unique2 on tenk1 tenk1_1
Filter: (unique2 <> 10)
(4 rows)
10
(1 row)
-reset enable_indexscan;
+reset enable_groupagg;
-- the hashed implementation is sensitive to child plans' tuple slot types
explain (costs off)
select * from int8_tbl intersect select q2, q1 from int8_tbl order by 1, 2;
-- check hashed implementation
set enable_hashagg = true;
-set enable_sort = false;
--- We've no way to check hashed UNION as the empty pathkeys in the Append are
--- fine to make use of Unique, which is cheaper than HashAggregate and we've
--- no means to disable Unique.
+set enable_groupagg = false;
+explain (costs off)
+select from generate_series(1,5) union select from generate_series(1,3);
+ QUERY PLAN
+----------------------------------------------------------------
+ HashAggregate
+ -> Append
+ -> Function Scan on generate_series
+ -> Function Scan on generate_series generate_series_1
+(4 rows)
+
explain (costs off)
select from generate_series(1,5) intersect select from generate_series(1,3);
QUERY PLAN
----------------------------------------------------------
- SetOp Intersect
+ HashSetOp Intersect
-> Function Scan on generate_series
-> Function Scan on generate_series generate_series_1
(3 rows)
+select from generate_series(1,5) union select from generate_series(1,3);
+--
+(1 row)
+
select from generate_series(1,5) union all select from generate_series(1,3);
--
(8 rows)
-- check sorted implementation
set enable_hashagg = false;
-set enable_sort = true;
+set enable_groupagg = true;
explain (costs off)
select from generate_series(1,5) union select from generate_series(1,3);
QUERY PLAN
(1 row)
reset enable_hashagg;
-reset enable_sort;
+reset enable_groupagg;
--
-- Check handling of a case with unknown constants. We don't guarantee
-- an undecorated constant will work in all cases, but historically this
-- DISTINCT can also trigger wrong answers with hash aggregation (bug #18465)
begin;
-set local enable_sort = off;
+set local enable_groupagg = off;
explain (costs off)
select f1, (select distinct min(t1.f1) from int4_tbl t1 where t1.f1 = t0.f1)
from int4_tbl t0;
-- Hash Aggregation Spill tests
--
-set enable_sort=false;
+set enable_groupagg=false;
set work_mem='64kB';
select unique1, count(*), sum(twothousand) from tenk1
order by sum(twothousand);
set work_mem to default;
-set enable_sort to default;
+set enable_groupagg to default;
--
-- Compare results between plans using sorting and plans using hash
-- Produce results with hash aggregation
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
set jit_above_cost = 0;
select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3
from agg_data_2k group by g/2;
-set enable_sort = true;
+set enable_groupagg = true;
set work_mem to default;
-- Compare group aggregation results to hash aggregation results
insert into bug_16784 select g/10, g from generate_series(1,40) g;
set work_mem='64kB';
-set enable_sort = false;
+set enable_groupagg = false;
select * from
(values (1),(2)) v(a),
-- Produce results with sorting.
-set enable_sort = true;
+set enable_groupagg = true;
set enable_hashagg = false;
set jit_above_cost = 0;
-- Produce results with hash aggregation.
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
explain (costs off)
select g100, g10, sum(g::numeric), count(*), max(g::text)
select g100, g10, sum(g::numeric), count(*), max(g::text)
from gs_data_1 group by cube (g1000, g100,g10);
-set enable_sort = true;
+set enable_groupagg = true;
set work_mem to default;
set hash_mem_multiplier to default;
SET enable_hashagg = off;
SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
SET enable_hashagg = on;
-SET enable_sort = off;
+SET enable_groupagg = off;
SELECT count(*) FROM (SELECT j FROM (SELECT * FROM testjsonb UNION ALL SELECT * FROM testjsonb) js GROUP BY j) js2;
SELECT distinct * FROM (values (jsonb '{}' || ''::text),('{}')) v(j);
-SET enable_sort = on;
+SET enable_groupagg = on;
RESET enable_hashagg;
-RESET enable_sort;
+RESET enable_groupagg;
DROP INDEX jidx;
DROP INDEX jidx_array;
-- Check behavior when subtype lacks a hash function
--
-set enable_sort = off; -- try to make it pick a hash setop implementation
+set enable_groupagg = off; -- try to make it pick a hash setop implementation
select '{(01,10)}'::varbitmultirange except select '{(10,11)}'::varbitmultirange;
-reset enable_sort;
+reset enable_groupagg;
--
-- OUT/INOUT/TABLE functions
create type varbitrange as range (subtype = varbit);
-set enable_sort = off; -- try to make it pick a hash setop implementation
+set enable_groupagg = off; -- try to make it pick a hash setop implementation
select '(01,10)'::varbitrange except select '(10,11)'::varbitrange;
-reset enable_sort;
+reset enable_groupagg;
--
-- OUT/INOUT/TABLE functions
-- Produce results with hash aggregation.
-SET enable_sort=FALSE;
+SET enable_groupagg=FALSE;
SET jit_above_cost=0;
CREATE TABLE distinct_hash_2 AS
SELECT DISTINCT (g%1000)::text FROM generate_series(0,9999) g;
-SET enable_sort=TRUE;
+SET enable_groupagg=TRUE;
SET work_mem TO DEFAULT;
-- Test rescan of a hashed SetOp node
--
begin;
-set local enable_sort = off;
+set local enable_groupagg = off;
explain (costs off)
select count(*) from
( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
-- this query will prefer a sorted setop unless we force it.
-set enable_indexscan to off;
+set enable_groupagg to off;
explain (costs off)
select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
-reset enable_indexscan;
+reset enable_groupagg;
-- the hashed implementation is sensitive to child plans' tuple slot types
explain (costs off)
-- check hashed implementation
set enable_hashagg = true;
-set enable_sort = false;
+set enable_groupagg = false;
--- We've no way to check hashed UNION as the empty pathkeys in the Append are
--- fine to make use of Unique, which is cheaper than HashAggregate and we've
--- no means to disable Unique.
+explain (costs off)
+select from generate_series(1,5) union select from generate_series(1,3);
explain (costs off)
select from generate_series(1,5) intersect select from generate_series(1,3);
+select from generate_series(1,5) union select from generate_series(1,3);
select from generate_series(1,5) union all select from generate_series(1,3);
select from generate_series(1,5) intersect select from generate_series(1,3);
select from generate_series(1,5) intersect all select from generate_series(1,3);
-- check sorted implementation
set enable_hashagg = false;
-set enable_sort = true;
+set enable_groupagg = true;
explain (costs off)
select from generate_series(1,5) union select from generate_series(1,3);
select from cte union select from cte;
reset enable_hashagg;
-reset enable_sort;
+reset enable_groupagg;
--
-- Check handling of a case with unknown constants. We don't guarantee