@@ -2728,29 +2728,20 @@ SELECT balk(hundred) FROM tenk1;
2728
2728
(1 row)
2729
2729
2730
2730
ROLLBACK;
2731
- -- GROUP BY optimization by reorder columns
2731
+ -- GROUP BY optimization by reordering GROUP BY clauses
2732
2732
CREATE TABLE btg AS SELECT
2733
- i % 100 AS x,
2734
- i % 100 AS y,
2733
+ i % 10 AS x,
2734
+ i % 10 AS y,
2735
2735
'abc' || i % 10 AS z,
2736
2736
i AS w
2737
- FROM generate_series(1,10000 ) AS i;
2738
- CREATE INDEX btg_x_y_idx ON btg(x,y);
2737
+ FROM generate_series(1, 100 ) AS i;
2738
+ CREATE INDEX btg_x_y_idx ON btg(x, y);
2739
2739
ANALYZE btg;
2740
- -- GROUP BY optimization by reorder columns by frequency
2741
- SET enable_hashagg=off;
2742
- SET max_parallel_workers= 0;
2743
- SET max_parallel_workers_per_gather = 0;
2744
- -- Utilize index scan ordering to avoid a Sort operation
2745
- EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY x,y;
2746
- QUERY PLAN
2747
- ------------------------------------------------
2748
- GroupAggregate
2749
- Group Key: x, y
2750
- -> Index Only Scan using btg_x_y_idx on btg
2751
- (3 rows)
2752
-
2753
- EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x;
2740
+ SET enable_hashagg = off;
2741
+ SET enable_seqscan = off;
2742
+ -- Utilize the ordering of index scan to avoid a Sort operation
2743
+ EXPLAIN (COSTS OFF)
2744
+ SELECT count(*) FROM btg GROUP BY y, x;
2754
2745
QUERY PLAN
2755
2746
------------------------------------------------
2756
2747
GroupAggregate
@@ -2759,121 +2750,103 @@ EXPLAIN (COSTS OFF) SELECT count(*) FROM btg GROUP BY y,x;
2759
2750
(3 rows)
2760
2751
2761
2752
-- Engage incremental sort
2762
- explain (COSTS OFF) SELECT x,y FROM btg GROUP BY x,y,z,w;
2753
+ EXPLAIN (COSTS OFF)
2754
+ SELECT count(*) FROM btg GROUP BY z, y, w, x;
2763
2755
QUERY PLAN
2764
2756
-------------------------------------------------
2765
- Group
2766
- Group Key: x, y, z, w
2767
- -> Incremental Sort
2768
- Sort Key: x, y, z, w
2769
- Presorted Key: x, y
2770
- -> Index Scan using btg_x_y_idx on btg
2771
- (6 rows)
2772
-
2773
- explain (COSTS OFF) SELECT x,y FROM btg GROUP BY z,y,w,x;
2774
- QUERY PLAN
2775
- -------------------------------------------------
2776
- Group
2757
+ GroupAggregate
2777
2758
Group Key: x, y, z, w
2778
2759
-> Incremental Sort
2779
2760
Sort Key: x, y, z, w
2780
2761
Presorted Key: x, y
2781
2762
-> Index Scan using btg_x_y_idx on btg
2782
2763
(6 rows)
2783
2764
2784
- explain (COSTS OFF) SELECT x,y FROM btg GROUP BY w,z,x,y;
2785
- QUERY PLAN
2786
- -------------------------------------------------
2787
- Group
2788
- Group Key: x, y, w, z
2789
- -> Incremental Sort
2790
- Sort Key: x, y, w, z
2791
- Presorted Key: x, y
2792
- -> Index Scan using btg_x_y_idx on btg
2793
- (6 rows)
2794
-
2795
- explain (COSTS OFF) SELECT x,y FROM btg GROUP BY w,x,z,y;
2765
+ -- Utilize the ordering of subquery scan to avoid a Sort operation
2766
+ EXPLAIN (COSTS OFF) SELECT count(*)
2767
+ FROM (SELECT * FROM btg ORDER BY x, y, w, z) AS q1
2768
+ GROUP BY w, x, z, y;
2796
2769
QUERY PLAN
2797
2770
-------------------------------------------------
2798
- Group
2799
- Group Key: x, y, w, z
2800
- -> Incremental Sort
2801
- Sort Key: x, y, w, z
2802
- Presorted Key: x, y
2803
- -> Index Scan using btg_x_y_idx on btg
2804
- (6 rows)
2805
-
2806
- -- Subqueries
2807
- explain (COSTS OFF) SELECT x,y
2808
- FROM (SELECT * FROM btg ORDER BY x,y,w,z) AS q1
2809
- GROUP BY (w,x,z,y);
2810
- QUERY PLAN
2811
- -------------------------------------------------
2812
- Group
2771
+ GroupAggregate
2813
2772
Group Key: btg.x, btg.y, btg.w, btg.z
2814
2773
-> Incremental Sort
2815
2774
Sort Key: btg.x, btg.y, btg.w, btg.z
2816
2775
Presorted Key: btg.x, btg.y
2817
2776
-> Index Scan using btg_x_y_idx on btg
2818
2777
(6 rows)
2819
2778
2820
- explain (COSTS OFF) SELECT x,y
2821
- FROM (SELECT * FROM btg ORDER BY x,y,w,z LIMIT 100) AS q1
2822
- GROUP BY (w,x,z,y);
2823
- QUERY PLAN
2824
- -------------------------------------------------------
2825
- Group
2826
- Group Key: btg.x, btg.y, btg.w, btg.z
2827
- -> Limit
2828
- -> Incremental Sort
2829
- Sort Key: btg.x, btg.y, btg.w, btg.z
2830
- Presorted Key: btg.x, btg.y
2831
- -> Index Scan using btg_x_y_idx on btg
2832
- (7 rows)
2779
+ -- Utilize the ordering of merge join to avoid a full Sort operation
2780
+ SET enable_hashjoin = off;
2781
+ SET enable_nestloop = off;
2782
+ EXPLAIN (COSTS OFF)
2783
+ SELECT count(*)
2784
+ FROM btg t1 JOIN btg t2 ON t1.z = t2.z AND t1.w = t2.w AND t1.x = t2.x
2785
+ GROUP BY t1.x, t1.y, t1.z, t1.w;
2786
+ QUERY PLAN
2787
+ -------------------------------------------------------------------------------
2788
+ GroupAggregate
2789
+ Group Key: t1.z, t1.w, t1.x, t1.y
2790
+ -> Incremental Sort
2791
+ Sort Key: t1.z, t1.w, t1.x, t1.y
2792
+ Presorted Key: t1.z, t1.w, t1.x
2793
+ -> Merge Join
2794
+ Merge Cond: ((t1.z = t2.z) AND (t1.w = t2.w) AND (t1.x = t2.x))
2795
+ -> Sort
2796
+ Sort Key: t1.z, t1.w, t1.x
2797
+ -> Index Scan using btg_x_y_idx on btg t1
2798
+ -> Sort
2799
+ Sort Key: t2.z, t2.w, t2.x
2800
+ -> Index Scan using btg_x_y_idx on btg t2
2801
+ (13 rows)
2833
2802
2803
+ RESET enable_nestloop;
2804
+ RESET enable_hashjoin;
2834
2805
-- Should work with and without GROUP-BY optimization
2835
- explain (COSTS OFF) SELECT x,y FROM btg GROUP BY w,x,z,y ORDER BY y,x,z,w;
2836
- QUERY PLAN
2837
- ------------------------------
2838
- Group
2806
+ EXPLAIN (COSTS OFF)
2807
+ SELECT count(*) FROM btg GROUP BY w, x, z, y ORDER BY y, x, z, w;
2808
+ QUERY PLAN
2809
+ -------------------------------------------------
2810
+ GroupAggregate
2839
2811
Group Key: y, x, z, w
2840
2812
-> Sort
2841
2813
Sort Key: y, x, z, w
2842
- -> Seq Scan on btg
2814
+ -> Index Scan using btg_x_y_idx on btg
2843
2815
(5 rows)
2844
2816
2845
2817
-- Utilize incremental sort to make the ORDER BY rule a bit cheaper
2846
- explain (COSTS OFF) SELECT x,w FROM btg GROUP BY w,x,y,z ORDER BY x*x,z;
2818
+ EXPLAIN (COSTS OFF)
2819
+ SELECT count(*) FROM btg GROUP BY w, x, y, z ORDER BY x*x, z;
2847
2820
QUERY PLAN
2848
2821
-------------------------------------------------------
2849
2822
Sort
2850
2823
Sort Key: ((x * x)), z
2851
- -> Group
2824
+ -> GroupAggregate
2852
2825
Group Key: x, y, w, z
2853
2826
-> Incremental Sort
2854
2827
Sort Key: x, y, w, z
2855
2828
Presorted Key: x, y
2856
2829
-> Index Scan using btg_x_y_idx on btg
2857
2830
(8 rows)
2858
2831
2859
- SET enable_incremental_sort = off;
2860
- -- The case when the number of incoming subtree path keys is more than
2832
+ -- Test the case where the number of incoming subtree path keys is more than
2861
2833
-- the number of grouping keys.
2862
- CREATE INDEX idx_y_x_z ON btg(y,x, w);
2834
+ CREATE INDEX btg_y_x_w_idx ON btg(y, x, w);
2863
2835
EXPLAIN (VERBOSE, COSTS OFF)
2864
- SELECT y,x,array_agg(distinct w) FROM btg WHERE y < 0 GROUP BY x,y;
2865
- QUERY PLAN
2866
- -----------------------------------------------------
2836
+ SELECT y, x, array_agg(distinct w)
2837
+ FROM btg WHERE y < 0 GROUP BY x, y;
2838
+ QUERY PLAN
2839
+ ---------------------------------------------------------
2867
2840
GroupAggregate
2868
2841
Output: y, x, array_agg(DISTINCT w)
2869
2842
Group Key: btg.y, btg.x
2870
- -> Index Only Scan using idx_y_x_z on public.btg
2843
+ -> Index Only Scan using btg_y_x_w_idx on public.btg
2871
2844
Output: y, x, w
2872
2845
Index Cond: (btg.y < 0)
2873
2846
(6 rows)
2874
2847
2875
- RESET enable_incremental_sort;
2876
- -- Check we don't pick aggregate path key instead of grouping path key
2848
+ -- Ensure that we do not select the aggregate pathkeys instead of the grouping
2849
+ -- pathkeys
2877
2850
CREATE TABLE group_agg_pk AS SELECT
2878
2851
i % 10 AS x,
2879
2852
i % 2 AS y,
@@ -2884,74 +2857,63 @@ FROM generate_series(1,100) AS i;
2884
2857
ANALYZE group_agg_pk;
2885
2858
SET enable_nestloop = off;
2886
2859
SET enable_hashjoin = off;
2887
- SELECT
2888
- c1.z, c1.w, string_agg(''::text, repeat(''::text, c1.f) ORDER BY c1.x,c1.y)
2889
- FROM group_agg_pk c1 JOIN group_agg_pk c2 ON ( c1.x = c2.f)
2860
+ EXPLAIN (COSTS OFF)
2861
+ SELECT avg( c1.f ORDER BY c1.x, c1.y)
2862
+ FROM group_agg_pk c1 JOIN group_agg_pk c2 ON c1.x = c2.x
2890
2863
GROUP BY c1.w, c1.z;
2891
- z | w | string_agg
2892
- ---+---+------------
2893
- 0 | 2 |
2894
- 1 | 2 |
2864
+ QUERY PLAN
2865
+ -----------------------------------------------------
2866
+ GroupAggregate
2867
+ Group Key: c1.w, c1.z
2868
+ -> Sort
2869
+ Sort Key: c1.w, c1.z, c1.x, c1.y
2870
+ -> Merge Join
2871
+ Merge Cond: (c1.x = c2.x)
2872
+ -> Sort
2873
+ Sort Key: c1.x
2874
+ -> Seq Scan on group_agg_pk c1
2875
+ -> Sort
2876
+ Sort Key: c2.x
2877
+ -> Seq Scan on group_agg_pk c2
2878
+ (12 rows)
2879
+
2880
+ SELECT avg(c1.f ORDER BY c1.x, c1.y)
2881
+ FROM group_agg_pk c1 JOIN group_agg_pk c2 ON c1.x = c2.x
2882
+ GROUP BY c1.w, c1.z;
2883
+ avg
2884
+ --------------------
2885
+ 4.0000000000000000
2886
+ 5.0000000000000000
2895
2887
(2 rows)
2896
2888
2897
2889
RESET enable_nestloop;
2898
2890
RESET enable_hashjoin;
2899
2891
DROP TABLE group_agg_pk;
2900
- -- The case, when scanning sort order correspond to aggregate sort order but
2901
- -- can not be found in the group-by list
2892
+ -- Test the case where the the ordering of scan matches the ordering within the
2893
+ -- aggregate but cannot be found in the group-by list
2902
2894
CREATE TABLE agg_sort_order (c1 int PRIMARY KEY, c2 int);
2903
- CREATE UNIQUE INDEX ON agg_sort_order(c2);
2904
- explain (costs off)
2895
+ CREATE UNIQUE INDEX agg_sort_order_c2_idx ON agg_sort_order(c2);
2896
+ INSERT INTO agg_sort_order SELECT i, i FROM generate_series(1,100)i;
2897
+ ANALYZE agg_sort_order;
2898
+ EXPLAIN (COSTS OFF)
2905
2899
SELECT array_agg(c1 ORDER BY c2),c2
2906
2900
FROM agg_sort_order WHERE c2 < 100 GROUP BY c1 ORDER BY 2;
2907
- QUERY PLAN
2908
- --------------------------------------------------------------------
2901
+ QUERY PLAN
2902
+ ----------------------------------------------------------------------------
2909
2903
Sort
2910
2904
Sort Key: c2
2911
2905
-> GroupAggregate
2912
2906
Group Key: c1
2913
2907
-> Sort
2914
2908
Sort Key: c1, c2
2915
- -> Bitmap Heap Scan on agg_sort_order
2916
- Recheck Cond: (c2 < 100)
2917
- -> Bitmap Index Scan on agg_sort_order_c2_idx
2918
- Index Cond: (c2 < 100)
2919
- (10 rows)
2909
+ -> Index Scan using agg_sort_order_c2_idx on agg_sort_order
2910
+ Index Cond: (c2 < 100)
2911
+ (8 rows)
2920
2912
2921
2913
DROP TABLE agg_sort_order CASCADE;
2922
- -- Check, that GROUP-BY reordering optimization can operate with pathkeys, built
2923
- -- by planner itself. For example, by MergeJoin.
2924
- SET enable_hashjoin = off;
2925
- SET enable_nestloop = off;
2926
- explain (COSTS OFF)
2927
- SELECT b1.x,b1.w FROM btg b1 JOIN btg b2 ON (b1.z=b2.z AND b1.w=b2.w)
2928
- GROUP BY b1.x,b1.z,b1.w ORDER BY b1.z, b1.w, b1.x*b1.x;
2929
- QUERY PLAN
2930
- -------------------------------------------------------------------
2931
- Incremental Sort
2932
- Sort Key: b1.z, b1.w, ((b1.x * b1.x))
2933
- Presorted Key: b1.z, b1.w
2934
- -> Group
2935
- Group Key: b1.z, b1.w, b1.x
2936
- -> Incremental Sort
2937
- Sort Key: b1.z, b1.w, b1.x
2938
- Presorted Key: b1.z, b1.w
2939
- -> Merge Join
2940
- Merge Cond: ((b1.z = b2.z) AND (b1.w = b2.w))
2941
- -> Sort
2942
- Sort Key: b1.z, b1.w
2943
- -> Seq Scan on btg b1
2944
- -> Sort
2945
- Sort Key: b2.z, b2.w
2946
- -> Seq Scan on btg b2
2947
- (16 rows)
2948
-
2949
- RESET enable_hashjoin;
2950
- RESET enable_nestloop;
2951
2914
DROP TABLE btg;
2952
2915
RESET enable_hashagg;
2953
- RESET max_parallel_workers;
2954
- RESET max_parallel_workers_per_gather;
2916
+ RESET enable_seqscan;
2955
2917
-- Secondly test the case of a parallel aggregate combiner function
2956
2918
-- returning NULL. For that use normal transition function, but a
2957
2919
-- combiner function returning NULL.
0 commit comments