@ -108,10 +108,6 @@ static double get_number_of_groups(PlannerInfo *root,
double path_rows ,
List * rollup_lists ,
List * rollup_groupclauses ) ;
static void set_grouped_rel_consider_parallel ( PlannerInfo * root ,
RelOptInfo * grouped_rel ,
PathTarget * target ,
const AggClauseCosts * agg_costs ) ;
static Size estimate_hashagg_tablesize ( Path * path ,
const AggClauseCosts * agg_costs ,
double dNumGroups ) ;
@ -255,29 +251,14 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
/*
* glob - > parallelModeNeeded should tell us whether it ' s necessary to
* impose the parallel mode restrictions , but we don ' t actually want to
* impose them unless we choose a parallel plan , so that people who
* mislabel their functions but don ' t use parallelism anyway aren ' t
* harmed . But when force_parallel_mode is set , we enable the restrictions
* whenever possible for testing purposes .
*
* glob - > wholePlanParallelSafe should tell us whether it ' s OK to stick a
* Gather node on top of the entire plan . However , it only needs to be
* accurate when force_parallel_mode is ' on ' or ' regress ' , so we don ' t
* bother doing the work otherwise . The value we set here is just a
* preliminary guess ; it may get changed from true to false later , but not
* vice versa .
* impose them unless we choose a parallel plan , so it is normally set
* only if a parallel plan is chosen ( see create_gather_plan ) . That way ,
* people who mislabel their functions but don ' t use parallelism anyway
* aren ' t harmed . But when force_parallel_mode is set , we enable the
* restrictions whenever possible for testing purposes .
*/
if ( force_parallel_mode = = FORCE_PARALLEL_OFF | | ! glob - > parallelModeOK )
{
glob - > parallelModeNeeded = false ;
glob - > wholePlanParallelSafe = false ; /* either false or don't care */
}
else
{
glob - > parallelModeNeeded = true ;
glob - > wholePlanParallelSafe =
! has_parallel_hazard ( ( Node * ) parse , false ) ;
}
glob - > parallelModeNeeded = glob - > parallelModeOK & &
( force_parallel_mode ! = FORCE_PARALLEL_OFF ) ;
/* Determine what fraction of the plan is likely to be scanned */
if ( cursorOptions & CURSOR_OPT_FAST_PLAN )
@ -327,20 +308,11 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
top_plan = materialize_finished_plan ( top_plan ) ;
}
/*
* At present , we don ' t copy subplans to workers . The presence of a
* subplan in one part of the plan doesn ' t preclude the use of parallelism
* in some other part of the plan , but it does preclude the possibility of
* regarding the entire plan parallel - safe .
*/
if ( glob - > subplans ! = NULL )
glob - > wholePlanParallelSafe = false ;
/*
* Optionally add a Gather node for testing purposes , provided this is
* actually a safe thing to do .
*/
if ( glo b- > wholePlanParallelS afe & &
if ( best_path - > parallel_safe & &
force_parallel_mode ! = FORCE_PARALLEL_OFF )
{
Gather * gather = makeNode ( Gather ) ;
@ -1925,6 +1897,21 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
*/
final_rel = fetch_upper_rel ( root , UPPERREL_FINAL , NULL ) ;
/*
* If the input rel is marked consider_parallel and there ' s nothing that ' s
* not parallel - safe in the LIMIT clause , then the final_rel can be marked
* consider_parallel as well . Note that if the query has rowMarks or is
* not a SELECT , consider_parallel will be false for every relation in the
* query .
*/
if ( current_rel - > consider_parallel & &
! has_parallel_hazard ( parse - > limitOffset , false ) & &
! has_parallel_hazard ( parse - > limitCount , false ) )
final_rel - > consider_parallel = true ;
/*
* Generate paths for the final rel .
*/
foreach ( lc , current_rel - > pathlist )
{
Path * path = ( Path * ) lfirst ( lc ) ;
@ -3203,56 +3190,6 @@ get_number_of_groups(PlannerInfo *root,
return dNumGroups ;
}
/*
* set_grouped_rel_consider_parallel
* Determine if it ' s safe to generate partial paths for grouping .
*/
static void
set_grouped_rel_consider_parallel ( PlannerInfo * root , RelOptInfo * grouped_rel ,
PathTarget * target ,
const AggClauseCosts * agg_costs )
{
Query * parse = root - > parse ;
Assert ( grouped_rel - > reloptkind = = RELOPT_UPPER_REL ) ;
/*
* If there are no aggregates or GROUP BY clause , then no parallel
* aggregation is possible . At present , it doesn ' t matter whether
* consider_parallel gets set in this case , because none of the upper rels
* on top of this one try to set the flag or examine it , so we just bail
* out as quickly as possible . We might need to be more clever here in
* the future .
*/
if ( ! parse - > hasAggs & & parse - > groupClause = = NIL )
return ;
/*
* Similarly , bail out quickly if GROUPING SETS are present ; we can ' t
* support those at present .
*/
if ( parse - > groupingSets )
return ;
/*
* If parallel - restricted functions are present in the target list or the
* HAVING clause , we cannot safely go parallel .
*/
if ( has_parallel_hazard ( ( Node * ) target - > exprs , false ) | |
has_parallel_hazard ( ( Node * ) parse - > havingQual , false ) )
return ;
/*
* If we have any non - partial - capable aggregates , or if any of them can ' t
* be serialized , we can ' t go parallel .
*/
if ( agg_costs - > hasNonPartial | | agg_costs - > hasNonSerial )
return ;
/* OK, consider parallelization */
grouped_rel - > consider_parallel = true ;
}
/*
* estimate_hashagg_tablesize
* estimate the number of bytes that a hash aggregate hashtable will
@ -3314,12 +3251,23 @@ create_grouping_paths(PlannerInfo *root,
double dNumPartialGroups = 0 ;
bool can_hash ;
bool can_sort ;
bool try_parallel_aggregation ;
ListCell * lc ;
/* For now, do all work in the (GROUP_AGG, NULL) upperrel */
grouped_rel = fetch_upper_rel ( root , UPPERREL_GROUP_AGG , NULL ) ;
/*
* If the input relation is not parallel - safe , then the grouped relation
* can ' t be parallel - safe , either . Otherwise , it ' s parallel - safe if the
* target list and HAVING quals are parallel - safe .
*/
if ( input_rel - > consider_parallel & &
! has_parallel_hazard ( ( Node * ) target - > exprs , false ) & &
! has_parallel_hazard ( ( Node * ) parse - > havingQual , false ) )
grouped_rel - > consider_parallel = true ;
/*
* Check for degenerate grouping .
*/
@ -3407,15 +3355,6 @@ create_grouping_paths(PlannerInfo *root,
rollup_lists ,
rollup_groupclauses ) ;
/*
* Partial paths in the input rel could allow us to perform aggregation in
* parallel . set_grouped_rel_consider_parallel ( ) will determine if it ' s
* going to be safe to do so .
*/
if ( input_rel - > partial_pathlist ! = NIL )
set_grouped_rel_consider_parallel ( root , grouped_rel ,
target , & agg_costs ) ;
/*
* Determine whether it ' s possible to perform sort - based implementations
* of grouping . ( Note that if groupClause is empty ,
@ -3447,6 +3386,46 @@ create_grouping_paths(PlannerInfo *root,
agg_costs . numOrderedAggs = = 0 & &
grouping_is_hashable ( parse - > groupClause ) ) ;
/*
* If grouped_rel - > consider_parallel is true , then paths that we generate
* for this grouping relation could be run inside of a worker , but that
* doesn ' t mean we can actually use the PartialAggregate / FinalizeAggregate
* execution strategy . Figure that out .
*/
if ( ! grouped_rel - > consider_parallel )
{
/* Not even parallel-safe. */
try_parallel_aggregation = false ;
}
else if ( input_rel - > partial_pathlist = = NIL )
{
/* Nothing to use as input for partial aggregate. */
try_parallel_aggregation = false ;
}
else if ( ! parse - > hasAggs & & parse - > groupClause = = NIL )
{
/*
* We don ' t know how to do parallel aggregation unless we have either
* some aggregates or a grouping clause .
*/
try_parallel_aggregation = false ;
}
else if ( parse - > groupingSets )
{
/* We don't know how to do grouping sets in parallel. */
try_parallel_aggregation = false ;
}
else if ( agg_costs . hasNonPartial | | agg_costs . hasNonSerial )
{
/* Insufficient support for partial mode. */
try_parallel_aggregation = false ;
}
else
{
/* Everything looks good. */
try_parallel_aggregation = true ;
}
/*
* Before generating paths for grouped_rel , we first generate any possible
* partial paths ; that way , later code can easily consider both parallel
@ -3455,7 +3434,7 @@ create_grouping_paths(PlannerInfo *root,
* Gather node on top is insufficient to create a final path , as would be
* the case for a scan / join rel .
*/
if ( grouped_rel - > consider_parallel )
if ( try_parallel_aggregation )
{
Path * cheapest_partial_path = linitial ( input_rel - > partial_pathlist ) ;
@ -3498,7 +3477,7 @@ create_grouping_paths(PlannerInfo *root,
if ( can_sort )
{
/* Checked in set_grouped_rel_consider_parallel() */
/* This was checked before setting try_parallel_aggregation */
Assert ( parse - > hasAggs | | parse - > groupClause ) ;
/*
@ -3831,6 +3810,16 @@ create_window_paths(PlannerInfo *root,
/* For now, do all work in the (WINDOW, NULL) upperrel */
window_rel = fetch_upper_rel ( root , UPPERREL_WINDOW , NULL ) ;
/*
* If the input relation is not parallel - safe , then the window relation
* can ' t be parallel - safe , either . Otherwise , we need to examine the
* target list and active windows for non - parallel - safe constructs .
*/
if ( input_rel - > consider_parallel & &
! has_parallel_hazard ( ( Node * ) output_target - > exprs , false ) & &
! has_parallel_hazard ( ( Node * ) activeWindows , false ) )
window_rel - > consider_parallel = true ;
/*
* Consider computing window functions starting from the existing
* cheapest - total path ( which will likely require a sort ) as well as any
@ -3986,6 +3975,15 @@ create_distinct_paths(PlannerInfo *root,
/* For now, do all work in the (DISTINCT, NULL) upperrel */
distinct_rel = fetch_upper_rel ( root , UPPERREL_DISTINCT , NULL ) ;
/*
* We don ' t compute anything at this level , so distinct_rel will be
* parallel - safe if the input rel is parallel - safe . In particular , if
* there is a DISTINCT ON ( . . . ) clause , any path for the input_rel will
* output those expressions , and will not be parallel - safe unless those
* expressions are parallel - safe .
*/
distinct_rel - > consider_parallel = input_rel - > consider_parallel ;
/* Estimate number of distinct rows there will be */
if ( parse - > groupClause | | parse - > groupingSets | | parse - > hasAggs | |
root - > hasHavingQual )
@ -4169,6 +4167,15 @@ create_ordered_paths(PlannerInfo *root,
/* For now, do all work in the (ORDERED, NULL) upperrel */
ordered_rel = fetch_upper_rel ( root , UPPERREL_ORDERED , NULL ) ;
/*
* If the input relation is not parallel - safe , then the ordered relation
* can ' t be parallel - safe , either . Otherwise , it ' s parallel - safe if the
* target list is parallel - safe .
*/
if ( input_rel - > consider_parallel & &
! has_parallel_hazard ( ( Node * ) target - > exprs , false ) )
ordered_rel - > consider_parallel = true ;
foreach ( lc , input_rel - > pathlist )
{
Path * path = ( Path * ) lfirst ( lc ) ;