@@ -73,7 +73,7 @@ static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
73
73
Index rti , RangeTblEntry * rte );
74
74
static void set_plain_rel_size (PlannerInfo * root , RelOptInfo * rel ,
75
75
RangeTblEntry * rte );
76
- static void create_parallel_paths (PlannerInfo * root , RelOptInfo * rel );
76
+ static void create_plain_partial_paths (PlannerInfo * root , RelOptInfo * rel );
77
77
static void set_rel_consider_parallel (PlannerInfo * root , RelOptInfo * rel ,
78
78
RangeTblEntry * rte );
79
79
static bool function_rte_parallel_ok (RangeTblEntry * rte );
@@ -447,6 +447,16 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
447
447
}
448
448
}
449
449
450
+ /*
451
+ * If this is a baserel, consider gathering any partial paths we may have
452
+ * created for it. (If we tried to gather inheritance children, we could
453
+ * end up with a very large number of gather nodes, each trying to grab
454
+ * its own pool of workers, so don't do this for otherrels. Instead,
455
+ * we'll consider gathering partial paths for the parent appendrel.)
456
+ */
457
+ if (rel -> reloptkind == RELOPT_BASEREL )
458
+ generate_gather_paths (root , rel );
459
+
450
460
/*
451
461
* Allow a plugin to editorialize on the set of Paths for this base
452
462
* relation. It could add new paths (such as CustomPaths) by calling
@@ -643,7 +653,7 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
643
653
644
654
/* If appropriate, consider parallel sequential scan */
645
655
if (rel -> consider_parallel && required_outer == NULL )
646
- create_parallel_paths (root , rel );
656
+ create_plain_partial_paths (root , rel );
647
657
648
658
/* Consider index scans */
649
659
create_index_paths (root , rel );
@@ -653,11 +663,11 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
653
663
}
654
664
655
665
/*
656
- * create_parallel_paths
657
- * Build parallel access paths for a plain relation
666
+ * create_plain_partial_paths
667
+ * Build partial access paths for parallel scan of a plain relation
658
668
*/
659
669
static void
660
- create_parallel_paths (PlannerInfo * root , RelOptInfo * rel )
670
+ create_plain_partial_paths (PlannerInfo * root , RelOptInfo * rel )
661
671
{
662
672
int parallel_degree = 1 ;
663
673
@@ -712,16 +722,6 @@ create_parallel_paths(PlannerInfo *root, RelOptInfo *rel)
712
722
713
723
/* Add an unordered partial path based on a parallel sequential scan. */
714
724
add_partial_path (rel , create_seqscan_path (root , rel , NULL , parallel_degree ));
715
-
716
- /*
717
- * If this is a baserel, consider gathering any partial paths we may have
718
- * just created. If we gathered an inheritance child, we could end up
719
- * with a very large number of gather nodes, each trying to grab its own
720
- * pool of workers, so don't do this in that case. Instead, we'll
721
- * consider gathering partial paths for the appendrel.
722
- */
723
- if (rel -> reloptkind == RELOPT_BASEREL )
724
- generate_gather_paths (root , rel );
725
725
}
726
726
727
727
/*
@@ -1262,9 +1262,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
1262
1262
appendpath = create_append_path (rel , partial_subpaths , NULL ,
1263
1263
parallel_degree );
1264
1264
add_partial_path (rel , (Path * ) appendpath );
1265
-
1266
- /* Consider gathering it. */
1267
- generate_gather_paths (root , rel );
1268
1265
}
1269
1266
1270
1267
/*
@@ -1970,6 +1967,10 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
1970
1967
* generate_gather_paths
1971
1968
* Generate parallel access paths for a relation by pushing a Gather on
1972
1969
* top of a partial path.
1970
+ *
1971
+ * This must not be called until after we're done creating all partial paths
1972
+ * for the specified relation. (Otherwise, add_partial_path might delete a
1973
+ * path that some GatherPath has a reference to.)
1973
1974
*/
1974
1975
void
1975
1976
generate_gather_paths (PlannerInfo * root , RelOptInfo * rel )
@@ -1983,7 +1984,9 @@ generate_gather_paths(PlannerInfo *root, RelOptInfo *rel)
1983
1984
1984
1985
/*
1985
1986
* The output of Gather is currently always unsorted, so there's only one
1986
- * partial path of interest: the cheapest one.
1987
+ * partial path of interest: the cheapest one. That will be the one at
1988
+ * the front of partial_pathlist because of the way add_partial_path
1989
+ * works.
1987
1990
*
1988
1991
* Eventually, we should have a Gather Merge operation that can merge
1989
1992
* multiple tuple streams together while preserving their ordering. We
@@ -2148,12 +2151,19 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
2148
2151
join_search_one_level (root , lev );
2149
2152
2150
2153
/*
2151
- * Do cleanup work on each just-processed rel.
2154
+ * Run generate_gather_paths() for each just-processed joinrel. We
2155
+ * could not do this earlier because both regular and partial paths
2156
+ * can get added to a particular joinrel at multiple times within
2157
+ * join_search_one_level. After that, we're done creating paths
2158
+ * for the joinrel, so run set_cheapest().
2152
2159
*/
2153
2160
foreach (lc , root -> join_rel_level [lev ])
2154
2161
{
2155
2162
rel = (RelOptInfo * ) lfirst (lc );
2156
2163
2164
+ /* Create GatherPaths for any useful partial paths for rel */
2165
+ generate_gather_paths (root , rel );
2166
+
2157
2167
/* Find and save the cheapest paths for this rel */
2158
2168
set_cheapest (rel );
2159
2169
0 commit comments