Skip to content

Commit 67a54b9

Browse files
author
Richard Guo
committed
Allow pushdown of HAVING clauses with grouping sets
In some cases, we may want to transfer a HAVING clause into WHERE in hopes of eliminating tuples before aggregation instead of after. Previously, we couldn't do this if there were any nonempty grouping sets, because we didn't have a way to tell if the HAVING clause referenced any columns that were nullable by the grouping sets, and moving such a clause into WHERE could potentially change the results. Now, with expressions marked nullable by grouping sets with the RT index of the RTE_GROUP RTE, it is much easier to identify those clauses that reference any nullable-by-grouping-sets columns: we just need to check if the RT index of the RTE_GROUP RTE is present in the clause. For other HAVING clauses, they can be safely pushed down. Author: Richard Guo Discussion: https://postgr.es/m/CAMbWs4-NpzPgtKU=hgnvyn+J-GanxQCjrUi7piNzZ=upiCV=2Q@mail.gmail.com
1 parent 828e94c commit 67a54b9

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
10471047
* cannot do so if the HAVING clause contains aggregates (obviously) or
10481048
* volatile functions (since a HAVING clause is supposed to be executed
10491049
* only once per group). We also can't do this if there are any nonempty
1050-
* grouping sets; moving such a clause into WHERE would potentially change
1051-
* the results, if any referenced column isn't present in all the grouping
1052-
* sets. (If there are only empty grouping sets, then the HAVING clause
1053-
* must be degenerate as discussed below.)
1050+
* grouping sets and the clause references any columns that are nullable
1051+
* by the grouping sets; moving such a clause into WHERE would potentially
1052+
* change the results. (If there are only empty grouping sets, then the
1053+
* HAVING clause must be degenerate as discussed below.)
10541054
*
10551055
* Also, it may be that the clause is so expensive to execute that we're
10561056
* better off doing it only once per group, despite the loss of
@@ -1088,15 +1088,16 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
10881088
{
10891089
Node *havingclause = (Node *) lfirst(l);
10901090

1091-
if ((parse->groupClause && parse->groupingSets) ||
1092-
contain_agg_clause(havingclause) ||
1091+
if (contain_agg_clause(havingclause) ||
10931092
contain_volatile_functions(havingclause) ||
1094-
contain_subplans(havingclause))
1093+
contain_subplans(havingclause) ||
1094+
(parse->groupClause && parse->groupingSets &&
1095+
bms_is_member(root->group_rtindex, pull_varnos(root, havingclause))))
10951096
{
10961097
/* keep it in HAVING */
10971098
newHaving = lappend(newHaving, havingclause);
10981099
}
1099-
else if (parse->groupClause && !parse->groupingSets)
1100+
else if (parse->groupClause)
11001101
{
11011102
Node *whereclause;
11021103

src/test/regress/expected/groupingsets.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,27 @@ explain (costs off)
860860
-> Seq Scan on gstest2
861861
(10 rows)
862862

863+
-- test pushdown of HAVING clause that does not reference any columns that are nullable by grouping sets
864+
explain (costs off)
865+
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
866+
QUERY PLAN
867+
---------------------------------
868+
GroupAggregate
869+
Group Key: a, b
870+
Group Key: a
871+
Filter: (b > 1)
872+
-> Sort
873+
Sort Key: a, b
874+
-> Seq Scan on gstest2
875+
Filter: (a > 1)
876+
(8 rows)
877+
878+
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
879+
a | b | count
880+
---+---+-------
881+
2 | 2 | 1
882+
(1 row)
883+
863884
-- HAVING with GROUPING queries
864885
select ten, grouping(ten) from onek
865886
group by grouping sets(ten) having grouping(ten) >= 0

src/test/regress/sql/groupingsets.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ explain (costs off)
279279
select v.c, (select count(*) from gstest2 group by () having v.c)
280280
from (values (false),(true)) v(c) order by v.c;
281281

282+
-- test pushdown of HAVING clause that does not reference any columns that are nullable by grouping sets
283+
explain (costs off)
284+
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
285+
select a, b, count(*) from gstest2 group by grouping sets ((a, b), (a)) having a > 1 and b > 1;
286+
282287
-- HAVING with GROUPING queries
283288
select ten, grouping(ten) from onek
284289
group by grouping sets(ten) having grouping(ten) >= 0

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy