Skip to content

Commit 598aa19

Browse files
committed
Still another try at fixing scanjoin_target insertion into parallel plans.
The previous code neglected the fact that the scanjoin_target might carry sortgroupref labelings that we need to absorb. Instead, do create_projection_path() unconditionally, and tweak the path's cost estimate after the fact. (I'm now convinced that we ought to refactor the way we account for sometimes not needing a separate projection step, but right now is not the time for that sort of cleanup.) Problem identified by Amit Kapila, patch by me.
1 parent 7e81a18 commit 598aa19

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,36 +1788,39 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
17881788
Path *subpath = (Path *) lfirst(lc);
17891789
Path *newpath;
17901790

1791+
/* Shouldn't have any parameterized paths anymore */
1792+
Assert(subpath->param_info == NULL);
1793+
17911794
/*
17921795
* We can't use apply_projection_to_path() here, because there
17931796
* could already be pointers to these paths, and therefore we
1794-
* cannot modify them in place. Instead, we must use
1795-
* create_projection_path(). The good news is this won't
1796-
* actually insert a Result node into the final plan unless
1797-
* it's needed, but the bad news is that it will charge for
1798-
* the node whether it's needed or not. Therefore, if the
1799-
* target list is already what we need it to be, just leave
1800-
* this partial path alone.
1797+
* dare not modify them in place. Instead, we must use
1798+
* create_projection_path() unconditionally.
18011799
*/
1802-
if (equal(scanjoin_target->exprs, subpath->pathtarget->exprs))
1803-
continue;
1804-
1805-
Assert(subpath->param_info == NULL);
18061800
newpath = (Path *) create_projection_path(root,
18071801
current_rel,
18081802
subpath,
18091803
scanjoin_target);
1810-
if (is_projection_capable_path(subpath))
1804+
1805+
/*
1806+
* Although create_projection_path() inserts a ProjectionPath
1807+
* unconditionally, create_projection_plan() will only insert
1808+
* a Result node if the subpath is not projection-capable, so
1809+
* we should discount the cost of that node if it will not
1810+
* actually get inserted. (This is pretty grotty but we can
1811+
* improve it later if it seems important.)
1812+
*/
1813+
if (equal(scanjoin_target->exprs, subpath->pathtarget->exprs))
18111814
{
1812-
/*
1813-
* Since the target lists differ, a projection path is
1814-
* essential, but it will disappear at plan creation time
1815-
* because the subpath is projection-capable. So avoid
1816-
* charging anything for the disappearing node.
1817-
*/
1815+
/* at most we need a relabeling of the subpath */
18181816
newpath->startup_cost = subpath->startup_cost;
18191817
newpath->total_cost = subpath->total_cost;
18201818
}
1819+
else if (is_projection_capable_path(subpath))
1820+
{
1821+
/* need to project, but we don't need a Result */
1822+
newpath->total_cost -= cpu_tuple_cost * subpath->rows;
1823+
}
18211824

18221825
lfirst(lc) = newpath;
18231826
}

src/test/regress/expected/select_parallel.out

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ create or replace function parallel_restricted(int) returns int as
66
-- Serializable isolation would disable parallel query, so explicitly use an
77
-- arbitrary other level.
88
begin isolation level repeatable read;
9-
-- setup parallel test
9+
-- encourage use of parallel plans
1010
set parallel_setup_cost=0;
1111
set parallel_tuple_cost=0;
12+
set min_parallel_relation_size=0;
1213
set max_parallel_workers_per_gather=4;
1314
explain (costs off)
1415
select count(*) from a_star;
@@ -71,6 +72,21 @@ select length(stringu1) from tenk1 group by length(stringu1);
7172
6
7273
(1 row)
7374

75+
explain (costs off)
76+
select stringu1, count(*) from tenk1 group by stringu1 order by stringu1;
77+
QUERY PLAN
78+
----------------------------------------------------
79+
Sort
80+
Sort Key: stringu1
81+
-> Finalize HashAggregate
82+
Group Key: stringu1
83+
-> Gather
84+
Workers Planned: 4
85+
-> Partial HashAggregate
86+
Group Key: stringu1
87+
-> Parallel Seq Scan on tenk1
88+
(9 rows)
89+
7490
-- test that parallel plan for aggregates is not selected when
7591
-- target list contains parallel restricted clause.
7692
explain (costs off)

src/test/regress/sql/select_parallel.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ create or replace function parallel_restricted(int) returns int as
99
-- arbitrary other level.
1010
begin isolation level repeatable read;
1111

12-
-- setup parallel test
12+
-- encourage use of parallel plans
1313
set parallel_setup_cost=0;
1414
set parallel_tuple_cost=0;
15+
set min_parallel_relation_size=0;
1516
set max_parallel_workers_per_gather=4;
1617

1718
explain (costs off)
@@ -29,6 +30,9 @@ explain (costs off)
2930
select length(stringu1) from tenk1 group by length(stringu1);
3031
select length(stringu1) from tenk1 group by length(stringu1);
3132

33+
explain (costs off)
34+
select stringu1, count(*) from tenk1 group by stringu1 order by stringu1;
35+
3236
-- test that parallel plan for aggregates is not selected when
3337
-- target list contains parallel restricted clause.
3438
explain (costs off)

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