-- -- PARTITION_AGGREGATE -- Test partitionwise aggregation on partitioned tables -- -- Note: to ensure plan stability, it's a good idea to make the partitions of -- any one partitioned table in this test all have different numbers of rows. --
-- Enable partitionwise aggregate, which by default is disabled. SET enable_partitionwise_aggregate TOtrue; -- Enable partitionwise join, which by default is disabled. SET enable_partitionwise_join TOtrue; -- Disable parallel plans. SET max_parallel_workers_per_gather TO0; -- Disable incremental sort, which can influence selected plans due to fuzz factor. SET enable_incremental_sort TO off;
-- -- Tests for list partitioned tables. -- CREATETABLE pagg_tab (a int, b int, c text, d int) PARTITION BY LIST(c); CREATETABLE pagg_tab_p1 PARTITION OF pagg_tab FORVALUESIN ('0000', '0001', '0002', '0003', '0004'); CREATETABLE pagg_tab_p2 PARTITION OF pagg_tab FORVALUESIN ('0005', '0006', '0007', '0008'); CREATETABLE pagg_tab_p3 PARTITION OF pagg_tab FORVALUESIN ('0009', '0010', '0011'); INSERTINTO pagg_tab SELECT i % 20, i % 30, to_char(i % 12, 'FM0000'), i % 30FROM generate_series(0, 2999) i; ANALYZE pagg_tab;
-- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUPBY c HAVING avg(d) < 15ORDERBY1, 2, 3; SELECT c, sum(a), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUPBY c HAVING avg(d) < 15ORDERBY1, 2, 3;
-- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUPBY a HAVING avg(d) < 15ORDERBY1, 2, 3; SELECT a, sum(b), avg(b), count(*), min(a), max(b) FROM pagg_tab GROUPBY a HAVING avg(d) < 15ORDERBY1, 2, 3;
-- Check with multiple columns in GROUP BY EXPLAIN (COSTS OFF) SELECT a, c, count(*) FROM pagg_tab GROUPBY a, c; -- Check with multiple columns in GROUP BY, order in GROUP BY is reversed EXPLAIN (COSTS OFF) SELECT a, c, count(*) FROM pagg_tab GROUPBY c, a; -- Check with multiple columns in GROUP BY, order in target-list is reversed EXPLAIN (COSTS OFF) SELECT c, a, count(*) FROM pagg_tab GROUPBY a, c;
-- Test when input relation for grouping is dummy EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab WHERE1 = 2GROUPBY c; SELECT c, sum(a) FROM pagg_tab WHERE1 = 2GROUPBY c; EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab WHERE c = 'x'GROUPBY c; SELECT c, sum(a) FROM pagg_tab WHERE c = 'x'GROUPBY c;
-- Test GroupAggregate paths by disabling hash aggregates. SET enable_hashagg TOfalse;
-- When GROUP BY clause matches full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUPBY1HAVING avg(d) < 15ORDERBY1, 2, 3; SELECT c, sum(a), avg(b), count(*) FROM pagg_tab GROUPBY1HAVING avg(d) < 15ORDERBY1, 2, 3;
-- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUPBY1HAVING avg(d) < 15ORDERBY1, 2, 3; SELECT a, sum(b), avg(b), count(*) FROM pagg_tab GROUPBY1HAVING avg(d) < 15ORDERBY1, 2, 3;
-- Test partitionwise grouping without any aggregates EXPLAIN (COSTS OFF) SELECT c FROM pagg_tab GROUPBY c ORDERBY1; SELECT c FROM pagg_tab GROUPBY c ORDERBY1; EXPLAIN (COSTS OFF) SELECT a FROM pagg_tab WHERE a < 3GROUPBY a ORDERBY1; SELECT a FROM pagg_tab WHERE a < 3GROUPBY a ORDERBY1;
-- Test partitionwise aggregation with ordered append path built from fractional paths EXPLAIN (COSTS OFF) SELECT count(*) FROM pagg_tab GROUPBY c ORDERBY c LIMIT1; SELECT count(*) FROM pagg_tab GROUPBY c ORDERBY c LIMIT1;
RESET enable_hashagg;
-- ROLLUP, partitionwise aggregation does not apply EXPLAIN (COSTS OFF) SELECT c, sum(a) FROM pagg_tab GROUPBY rollup(c) ORDERBY1, 2;
-- ORDERED SET within the aggregate. -- Full aggregation; since all the rows that belong to the same group come -- from the same partition, having an ORDER BY within the aggregate doesn't -- make any difference. EXPLAIN (COSTS OFF) SELECT c, sum(b orderby a) FROM pagg_tab GROUPBY c ORDERBY1, 2; -- Since GROUP BY clause does not match with PARTITION KEY; we need to do -- partial aggregation. However, ORDERED SET are not partial safe and thus -- partitionwise aggregation plan is not generated. EXPLAIN (COSTS OFF) SELECT a, sum(b orderby a) FROM pagg_tab GROUPBY a ORDERBY1, 2;
-- JOIN query
CREATETABLE pagg_tab1(x int, y int) PARTITION BY RANGE(x); CREATETABLE pagg_tab1_p1 PARTITION OF pagg_tab1 FORVALUESFROM (0) TO (10); CREATETABLE pagg_tab1_p2 PARTITION OF pagg_tab1 FORVALUESFROM (10) TO (20); CREATETABLE pagg_tab1_p3 PARTITION OF pagg_tab1 FORVALUESFROM (20) TO (30);
CREATETABLE pagg_tab2(x int, y int) PARTITION BY RANGE(y); CREATETABLE pagg_tab2_p1 PARTITION OF pagg_tab2 FORVALUESFROM (0) TO (10); CREATETABLE pagg_tab2_p2 PARTITION OF pagg_tab2 FORVALUESFROM (10) TO (20); CREATETABLE pagg_tab2_p3 PARTITION OF pagg_tab2 FORVALUESFROM (20) TO (30);
INSERTINTO pagg_tab1 SELECT i % 30, i % 20FROM generate_series(0, 299, 2) i; INSERTINTO pagg_tab2 SELECT i % 20, i % 30FROM generate_series(0, 299, 3) i;
ANALYZE pagg_tab1; ANALYZE pagg_tab2;
-- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.x ORDERBY1, 2, 3; SELECT t1.x, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.x ORDERBY1, 2, 3;
-- Check with whole-row reference; partitionwise aggregation does not apply EXPLAIN (COSTS OFF) SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.x ORDERBY1, 2, 3; SELECT t1.x, sum(t1.y), count(t1) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.x ORDERBY1, 2, 3;
-- GROUP BY having other matching key EXPLAIN (COSTS OFF) SELECT t2.y, sum(t1.y), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t2.y ORDERBY1, 2, 3;
-- When GROUP BY clause does not match; partial aggregation is performed for each partition. -- Also test GroupAggregate paths by disabling hash aggregates. SET enable_hashagg TOfalse; EXPLAIN (COSTS OFF) SELECT t1.y, sum(t1.x), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.y HAVING avg(t1.x) > 10ORDERBY1, 2, 3; SELECT t1.y, sum(t1.x), count(*) FROM pagg_tab1 t1, pagg_tab2 t2 WHERE t1.x = t2.y GROUPBY t1.y HAVING avg(t1.x) > 10ORDERBY1, 2, 3;
RESET enable_hashagg;
-- Check with LEFT/RIGHT/FULL OUTER JOINs which produces NULL values for -- aggregation
-- LEFT JOIN, should produce partial partitionwise aggregation plan as -- GROUP BY is on nullable column EXPLAIN (COSTS OFF) SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFTJOIN pagg_tab2 b ON a.x = b.y GROUPBY b.y ORDERBY1 NULLS LAST; SELECT b.y, sum(a.y) FROM pagg_tab1 a LEFTJOIN pagg_tab2 b ON a.x = b.y GROUPBY b.y ORDERBY1 NULLS LAST;
-- RIGHT JOIN, should produce full partitionwise aggregation plan as -- GROUP BY is on non-nullable column EXPLAIN (COSTS OFF) SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHTJOIN pagg_tab2 b ON a.x = b.y GROUPBY b.y ORDERBY1 NULLS LAST; SELECT b.y, sum(a.y) FROM pagg_tab1 a RIGHTJOIN pagg_tab2 b ON a.x = b.y GROUPBY b.y ORDERBY1 NULLS LAST;
-- FULL JOIN, should produce partial partitionwise aggregation plan as -- GROUP BY is on nullable column EXPLAIN (COSTS OFF) SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTERJOIN pagg_tab2 b ON a.x = b.y GROUPBY a.x ORDERBY1 NULLS LAST; SELECT a.x, sum(b.x) FROM pagg_tab1 a FULL OUTERJOIN pagg_tab2 b ON a.x = b.y GROUPBY a.x ORDERBY1 NULLS LAST;
-- LEFT JOIN, with dummy relation on right side, ideally -- should produce full partitionwise aggregation plan as GROUP BY is on -- non-nullable columns. -- But right now we are unable to do partitionwise join in this case. EXPLAIN (COSTS OFF) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFTJOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5or b.y < 20GROUPBY a.x, b.y ORDERBY1, 2; SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFTJOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5or b.y < 20GROUPBY a.x, b.y ORDERBY1, 2;
-- FULL JOIN, with dummy relations on both sides, ideally -- should produce partial partitionwise aggregation plan as GROUP BY is on -- nullable columns. -- But right now we are unable to do partitionwise join in this case. EXPLAIN (COSTS OFF) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5or b.y < 20GROUPBY a.x, b.y ORDERBY1, 2; SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOIN (SELECT * FROM pagg_tab2 WHERE y > 10) b ON a.x = b.y WHERE a.x > 5or b.y < 20GROUPBY a.x, b.y ORDERBY1, 2;
-- Empty join relation because of empty outer side, no partitionwise agg plan EXPLAIN (COSTS OFF) SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1AND x = 2) a LEFTJOIN pagg_tab2 b ON a.x = b.y GROUPBY a.x, a.y ORDERBY1, 2; SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1AND x = 2) a LEFTJOIN pagg_tab2 b ON a.x = b.y GROUPBY a.x, a.y ORDERBY1, 2;
-- Partition by multiple columns
CREATETABLE pagg_tab_m (a int, b int, c int) PARTITION BY RANGE(a, ((a+b)/2)); CREATETABLE pagg_tab_m_p1 PARTITION OF pagg_tab_m FORVALUESFROM (0, 0) TO (12, 12); CREATETABLE pagg_tab_m_p2 PARTITION OF pagg_tab_m FORVALUESFROM (12, 12) TO (22, 22); CREATETABLE pagg_tab_m_p3 PARTITION OF pagg_tab_m FORVALUESFROM (22, 22) TO (30, 30); INSERTINTO pagg_tab_m SELECT i % 30, i % 40, i % 50FROM generate_series(0, 2999) i; ANALYZE pagg_tab_m;
-- Partial aggregation as GROUP BY clause does not match with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY a HAVING avg(c) < 22ORDERBY1, 2, 3; SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY a HAVING avg(c) < 22ORDERBY1, 2, 3;
-- Full aggregation as GROUP BY clause matches with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY a, (a+b)/2HAVING sum(b) < 50ORDERBY1, 2, 3; SELECT a, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY a, (a+b)/2HAVING sum(b) < 50ORDERBY1, 2, 3;
-- Full aggregation as PARTITION KEY is part of GROUP BY clause EXPLAIN (COSTS OFF) SELECT a, c, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY (a+b)/2, 2, 1HAVING sum(b) = 50AND avg(c) > 25ORDERBY1, 2, 3; SELECT a, c, sum(b), avg(c), count(*) FROM pagg_tab_m GROUPBY (a+b)/2, 2, 1HAVING sum(b) = 50AND avg(c) > 25ORDERBY1, 2, 3;
-- Test with multi-level partitioning scheme
CREATETABLE pagg_tab_ml (a int, b int, c text) PARTITION BY RANGE(a); CREATETABLE pagg_tab_ml_p1 PARTITION OF pagg_tab_ml FORVALUESFROM (0) TO (12); CREATETABLE pagg_tab_ml_p2 PARTITION OF pagg_tab_ml FORVALUESFROM (12) TO (20) PARTITION BY LIST (c); CREATETABLE pagg_tab_ml_p2_s1 PARTITION OF pagg_tab_ml_p2 FORVALUESIN ('0000', '0001', '0002'); CREATETABLE pagg_tab_ml_p2_s2 PARTITION OF pagg_tab_ml_p2 FORVALUESIN ('0003');
-- This level of partitioning has different column positions than the parent CREATETABLE pagg_tab_ml_p3(b int, c text, a int) PARTITION BY RANGE (b); CREATETABLE pagg_tab_ml_p3_s1(c text, a int, b int); CREATETABLE pagg_tab_ml_p3_s2 PARTITION OF pagg_tab_ml_p3 FORVALUESFROM (7) TO (10);
ALTERTABLE pagg_tab_ml_p3 ATTACH PARTITION pagg_tab_ml_p3_s1 FORVALUESFROM (0) TO (7); ALTERTABLE pagg_tab_ml ATTACH PARTITION pagg_tab_ml_p3 FORVALUESFROM (20) TO (30);
INSERTINTO pagg_tab_ml SELECT i % 30, i % 10, to_char(i % 4, 'FM0000') FROM generate_series(0, 29999) i; ANALYZE pagg_tab_ml;
-- For Parallel Append SET max_parallel_workers_per_gather TO2; SET parallel_setup_cost = 0;
-- Full aggregation at level 1 as GROUP BY clause matches with PARTITION KEY -- for level 1 only. For subpartitions, GROUP BY clause does not match with -- PARTITION KEY, but still we do not see a partial aggregation as array_agg() -- is not partial agg safe. EXPLAIN (COSTS OFF) SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3; SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3;
-- Without ORDER BY clause, to test Gather at top-most path EXPLAIN (COSTS OFF) SELECT a, sum(b), array_agg(distinct c), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3;
RESET parallel_setup_cost;
-- Full aggregation at level 1 as GROUP BY clause matches with PARTITION KEY -- for level 1 only. For subpartitions, GROUP BY clause does not match with -- PARTITION KEY, thus we will have a partial aggregation for them. EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3; SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3;
-- Partial aggregation at all levels as GROUP BY clause does not match with -- PARTITION KEY EXPLAIN (COSTS OFF) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUPBY b ORDERBY1, 2, 3; SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUPBY b HAVING avg(a) < 15ORDERBY1, 2, 3;
-- Full aggregation at all levels as GROUP BY clause matches with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a, b, c HAVING avg(b) > 7ORDERBY1, 2, 3; SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a, b, c HAVING avg(b) > 7ORDERBY1, 2, 3;
-- Parallelism within partitionwise aggregates
SET min_parallel_table_scan_size TO'8kB'; SET parallel_setup_cost TO0;
-- Full aggregation at level 1 as GROUP BY clause matches with PARTITION KEY -- for level 1 only. For subpartitions, GROUP BY clause does not match with -- PARTITION KEY, thus we will have a partial aggregation for them. EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3; SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a HAVING avg(b) < 3ORDERBY1, 2, 3;
-- Partial aggregation at all levels as GROUP BY clause does not match with -- PARTITION KEY EXPLAIN (COSTS OFF) SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUPBY b ORDERBY1, 2, 3; SELECT b, sum(a), count(*) FROM pagg_tab_ml GROUPBY b HAVING avg(a) < 15ORDERBY1, 2, 3;
-- Full aggregation at all levels as GROUP BY clause matches with PARTITION KEY EXPLAIN (COSTS OFF) SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a, b, c HAVING avg(b) > 7ORDERBY1, 2, 3; SELECT a, sum(b), count(*) FROM pagg_tab_ml GROUPBY a, b, c HAVING avg(b) > 7ORDERBY1, 2, 3;
-- Parallelism within partitionwise aggregates (single level)
-- Add few parallel setup cost, so that we will see a plan which gathers -- partially created paths even for full aggregation and sticks a single Gather -- followed by finalization step. -- Without this, the cost of doing partial aggregation + Gather + finalization -- for each partition and then Append over it turns out to be same and this -- wins as we add it first. This parallel_setup_cost plays a vital role in -- costing such plans. SET parallel_setup_cost TO10;
CREATETABLE pagg_tab_para(x int, y int) PARTITION BY RANGE(x); CREATETABLE pagg_tab_para_p1 PARTITION OF pagg_tab_para FORVALUESFROM (0) TO (12); CREATETABLE pagg_tab_para_p2 PARTITION OF pagg_tab_para FORVALUESFROM (12) TO (22); CREATETABLE pagg_tab_para_p3 PARTITION OF pagg_tab_para FORVALUESFROM (22) TO (30);
INSERTINTO pagg_tab_para SELECT i % 30, i % 20FROM generate_series(0, 29999) i;
ANALYZE pagg_tab_para;
-- When GROUP BY clause matches; full aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3; SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3;
-- When GROUP BY clause does not match; partial aggregation is performed for each partition. EXPLAIN (COSTS OFF) SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUPBY y HAVING avg(x) < 12ORDERBY1, 2, 3; SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUPBY y HAVING avg(x) < 12ORDERBY1, 2, 3;
-- Test when parent can produce parallel paths but not any (or some) of its children -- (Use one more aggregate to tilt the cost estimates for the plan we want) ALTERTABLE pagg_tab_para_p1 SET (parallel_workers = 0); ALTERTABLE pagg_tab_para_p3 SET (parallel_workers = 0); ANALYZE pagg_tab_para;
EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), sum(x+y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3; SELECT x, sum(y), avg(y), sum(x+y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3;
ALTERTABLE pagg_tab_para_p2 SET (parallel_workers = 0); ANALYZE pagg_tab_para;
EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), sum(x+y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3; SELECT x, sum(y), avg(y), sum(x+y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3;
-- Reset parallelism parameters to get partitionwise aggregation plan.
RESET min_parallel_table_scan_size;
RESET parallel_setup_cost;
EXPLAIN (COSTS OFF) SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3; SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUPBY x HAVING avg(y) < 7ORDERBY1, 2, 3;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.