@@ -298,12 +298,18 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
298298 */
299299 set_subquery_size_estimates (root , rel );
300300
301+ /*
302+ * Since we may want to add a partial path to this relation, we must
303+ * set its consider_parallel flag correctly.
304+ */
305+ final_rel = fetch_upper_rel (subroot , UPPERREL_FINAL , NULL );
306+ rel -> consider_parallel = final_rel -> consider_parallel ;
307+
301308 /*
302309 * For the moment, we consider only a single Path for the subquery.
303310 * This should change soon (make it look more like
304311 * set_subquery_pathlist).
305312 */
306- final_rel = fetch_upper_rel (subroot , UPPERREL_FINAL , NULL );
307313 subpath = get_cheapest_fractional_path (final_rel ,
308314 root -> tuple_fraction );
309315
@@ -320,6 +326,23 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
320326
321327 add_path (rel , path );
322328
329+ /*
330+ * If we have a partial path for the child relation, we can use that
331+ * to build a partial path for this relation. But there's no point in
332+ * considering any path but the cheapest.
333+ */
334+ if (final_rel -> partial_pathlist != NIL )
335+ {
336+ Path * partial_subpath ;
337+ Path * partial_path ;
338+
339+ partial_subpath = linitial (final_rel -> partial_pathlist );
340+ partial_path = (Path * )
341+ create_subqueryscan_path (root , rel , partial_subpath ,
342+ NIL , NULL );
343+ add_partial_path (rel , partial_path );
344+ }
345+
323346 /*
324347 * Estimate number of groups if caller wants it. If the subquery used
325348 * grouping or aggregation, its output is probably mostly unique
@@ -552,6 +575,9 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
552575 double save_fraction = root -> tuple_fraction ;
553576 ListCell * lc ;
554577 List * pathlist = NIL ;
578+ List * partial_pathlist = NIL ;
579+ bool partial_paths_valid = true;
580+ bool consider_parallel = true;
555581 List * rellist ;
556582 List * tlist_list ;
557583 List * tlist ;
@@ -591,18 +617,34 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
591617
592618 * pTargetList = tlist ;
593619
594- /* Build path list and relid set. */
620+ /* Build path lists and relid set. */
595621 foreach (lc , rellist )
596622 {
597623 RelOptInfo * rel = lfirst (lc );
598624
599625 pathlist = lappend (pathlist , rel -> cheapest_total_path );
626+
627+ if (consider_parallel )
628+ {
629+ if (!rel -> consider_parallel )
630+ {
631+ consider_parallel = false;
632+ partial_paths_valid = false;
633+ }
634+ else if (rel -> partial_pathlist == NIL )
635+ partial_paths_valid = false;
636+ else
637+ partial_pathlist = lappend (partial_pathlist ,
638+ linitial (rel -> partial_pathlist ));
639+ }
640+
600641 relids = bms_union (relids , rel -> relids );
601642 }
602643
603644 /* Build result relation. */
604645 result_rel = fetch_upper_rel (root , UPPERREL_SETOP , relids );
605646 result_rel -> reltarget = create_pathtarget (root , tlist );
647+ result_rel -> consider_parallel = consider_parallel ;
606648
607649 /*
608650 * Append the child results together.
@@ -626,6 +668,53 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
626668 */
627669 result_rel -> rows = path -> rows ;
628670
671+ /*
672+ * Now consider doing the same thing using the partial paths plus Append
673+ * plus Gather.
674+ */
675+ if (partial_paths_valid )
676+ {
677+ Path * ppath ;
678+ ListCell * lc ;
679+ int parallel_workers = 0 ;
680+
681+ /* Find the highest number of workers requested for any subpath. */
682+ foreach (lc , partial_pathlist )
683+ {
684+ Path * path = lfirst (lc );
685+
686+ parallel_workers = Max (parallel_workers , path -> parallel_workers );
687+ }
688+ Assert (parallel_workers > 0 );
689+
690+ /*
691+ * If the use of parallel append is permitted, always request at least
692+ * log2(# of children) paths. We assume it can be useful to have
693+ * extra workers in this case because they will be spread out across
694+ * the children. The precise formula is just a guess; see
695+ * add_paths_to_append_rel.
696+ */
697+ if (enable_parallel_append )
698+ {
699+ parallel_workers = Max (parallel_workers ,
700+ fls (list_length (partial_pathlist )));
701+ parallel_workers = Min (parallel_workers ,
702+ max_parallel_workers_per_gather );
703+ }
704+ Assert (parallel_workers > 0 );
705+
706+ ppath = (Path * )
707+ create_append_path (result_rel , NIL , partial_pathlist ,
708+ NULL , parallel_workers , enable_parallel_append ,
709+ NIL , -1 );
710+ ppath = (Path * )
711+ create_gather_path (root , result_rel , ppath ,
712+ result_rel -> reltarget , NULL , NULL );
713+ if (!op -> all )
714+ ppath = make_union_unique (op , ppath , tlist , root );
715+ add_path (result_rel , ppath );
716+ }
717+
629718 /* Undo effects of possibly forcing tuple_fraction to 0 */
630719 root -> tuple_fraction = save_fraction ;
631720
0 commit comments