summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2016-04-12 20:24:55 +0000
committerRobert Haas2016-04-12 20:25:55 +0000
commitdeb71fa9713dfe374a74fc58a5d298b5f25da3f5 (patch)
tree8fc5617711af56dc7d4ee346b07fb7164b7a921a
parent46d73e0d65eef19e25bb0d31f1e5c23ff40a3444 (diff)
Fix costing for parallel aggregation.
The original patch kind of ignored the fact that we were doing something different from a costing point of view, but nobody noticed. This patch fixes that oversight. David Rowley
-rw-r--r--src/backend/optimizer/plan/planner.c39
-rw-r--r--src/backend/optimizer/util/clauses.c75
-rw-r--r--src/include/optimizer/clauses.h3
3 files changed, 92 insertions, 25 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 7c1e3d6bbf..9377550ad6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3262,6 +3262,8 @@ create_grouping_paths(PlannerInfo *root,
RelOptInfo *grouped_rel;
PathTarget *partial_grouping_target = NULL;
AggClauseCosts agg_costs;
+ AggClauseCosts agg_partial_costs; /* parallel only */
+ AggClauseCosts agg_final_costs; /* parallel only */
Size hashaggtablesize;
double dNumGroups;
double dNumPartialGroups = 0;
@@ -3346,8 +3348,10 @@ create_grouping_paths(PlannerInfo *root,
MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
if (parse->hasAggs)
{
- count_agg_clauses(root, (Node *) target->exprs, &agg_costs);
- count_agg_clauses(root, parse->havingQual, &agg_costs);
+ count_agg_clauses(root, (Node *) target->exprs, &agg_costs, true,
+ false, false);
+ count_agg_clauses(root, parse->havingQual, &agg_costs, true, false,
+ false);
}
/*
@@ -3422,6 +3426,25 @@ create_grouping_paths(PlannerInfo *root,
NIL,
NIL);
+ /*
+ * Collect statistics about aggregates for estimating costs of
+ * performing aggregation in parallel.
+ */
+ MemSet(&agg_partial_costs, 0, sizeof(AggClauseCosts));
+ MemSet(&agg_final_costs, 0, sizeof(AggClauseCosts));
+ if (parse->hasAggs)
+ {
+ /* partial phase */
+ count_agg_clauses(root, (Node *) partial_grouping_target->exprs,
+ &agg_partial_costs, false, false, true);
+
+ /* final phase */
+ count_agg_clauses(root, (Node *) target->exprs, &agg_final_costs,
+ true, true, true);
+ count_agg_clauses(root, parse->havingQual, &agg_final_costs, true,
+ true, true);
+ }
+
if (can_sort)
{
/* Checked in set_grouped_rel_consider_parallel() */
@@ -3457,7 +3480,7 @@ create_grouping_paths(PlannerInfo *root,
parse->groupClause ? AGG_SORTED : AGG_PLAIN,
parse->groupClause,
NIL,
- &agg_costs,
+ &agg_partial_costs,
dNumPartialGroups,
false,
false,
@@ -3482,7 +3505,7 @@ create_grouping_paths(PlannerInfo *root,
hashaggtablesize =
estimate_hashagg_tablesize(cheapest_partial_path,
- &agg_costs,
+ &agg_partial_costs,
dNumPartialGroups);
/*
@@ -3499,7 +3522,7 @@ create_grouping_paths(PlannerInfo *root,
AGG_HASHED,
parse->groupClause,
NIL,
- &agg_costs,
+ &agg_partial_costs,
dNumPartialGroups,
false,
false,
@@ -3631,7 +3654,7 @@ create_grouping_paths(PlannerInfo *root,
parse->groupClause ? AGG_SORTED : AGG_PLAIN,
parse->groupClause,
(List *) parse->havingQual,
- &agg_costs,
+ &agg_final_costs,
dNumGroups,
true,
true,
@@ -3691,7 +3714,7 @@ create_grouping_paths(PlannerInfo *root,
Path *path = (Path *) linitial(grouped_rel->partial_pathlist);
hashaggtablesize = estimate_hashagg_tablesize(path,
- &agg_costs,
+ &agg_final_costs,
dNumGroups);
if (hashaggtablesize < work_mem * 1024L)
@@ -3713,7 +3736,7 @@ create_grouping_paths(PlannerInfo *root,
AGG_HASHED,
parse->groupClause,
(List *) parse->havingQual,
- &agg_costs,
+ &agg_final_costs,
dNumGroups,
true,
true,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 5674a73dfe..759566ad46 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -61,6 +61,9 @@ typedef struct
{
PlannerInfo *root;
AggClauseCosts *costs;
+ bool finalizeAggs;
+ bool combineStates;
+ bool serialStates;
} count_agg_clauses_context;
typedef struct
@@ -540,12 +543,16 @@ contain_agg_clause_walker(Node *node, void *context)
* are no subqueries. There mustn't be outer-aggregate references either.
*/
void
-count_agg_clauses(PlannerInfo *root, Node *clause, AggClauseCosts *costs)
+count_agg_clauses(PlannerInfo *root, Node *clause, AggClauseCosts *costs,
+ bool finalizeAggs, bool combineStates, bool serialStates)
{
count_agg_clauses_context context;
context.root = root;
context.costs = costs;
+ context.finalizeAggs = finalizeAggs;
+ context.combineStates = combineStates;
+ context.serialStates = serialStates;
(void) count_agg_clauses_walker(clause, &context);
}
@@ -562,6 +569,9 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
Form_pg_aggregate aggform;
Oid aggtransfn;
Oid aggfinalfn;
+ Oid aggcombinefn;
+ Oid aggserialfn;
+ Oid aggdeserialfn;
Oid aggtranstype;
int32 aggtransspace;
QualCost argcosts;
@@ -583,6 +593,9 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
+ aggcombinefn = aggform->aggcombinefn;
+ aggserialfn = aggform->aggserialfn;
+ aggdeserialfn = aggform->aggdeserialfn;
aggtranstype = aggform->aggtranstype;
aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
@@ -592,28 +605,58 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
if (aggref->aggorder != NIL || aggref->aggdistinct != NIL)
costs->numOrderedAggs++;
- /* add component function execution costs to appropriate totals */
- costs->transCost.per_tuple += get_func_cost(aggtransfn) * cpu_operator_cost;
- if (OidIsValid(aggfinalfn))
- costs->finalCost += get_func_cost(aggfinalfn) * cpu_operator_cost;
+ /*
+ * Add the appropriate component function execution costs to
+ * appropriate totals.
+ */
+ if (context->combineStates)
+ {
+ /* charge for combining previously aggregated states */
+ costs->transCost.per_tuple += get_func_cost(aggcombinefn) * cpu_operator_cost;
- /* also add the input expressions' cost to per-input-row costs */
- cost_qual_eval_node(&argcosts, (Node *) aggref->args, context->root);
- costs->transCost.startup += argcosts.startup;
- costs->transCost.per_tuple += argcosts.per_tuple;
+ /* charge for deserialization, when appropriate */
+ if (context->serialStates && OidIsValid(aggdeserialfn))
+ costs->transCost.per_tuple += get_func_cost(aggdeserialfn) * cpu_operator_cost;
+ }
+ else
+ costs->transCost.per_tuple += get_func_cost(aggtransfn) * cpu_operator_cost;
+
+ if (context->finalizeAggs)
+ {
+ if (OidIsValid(aggfinalfn))
+ costs->finalCost += get_func_cost(aggfinalfn) * cpu_operator_cost;
+ }
+ else if (context->serialStates)
+ {
+ if (OidIsValid(aggserialfn))
+ costs->finalCost += get_func_cost(aggserialfn) * cpu_operator_cost;
+ }
/*
- * Add any filter's cost to per-input-row costs.
- *
- * XXX Ideally we should reduce input expression costs according to
- * filter selectivity, but it's not clear it's worth the trouble.
+ * Some costs will already have been incurred by the initial aggregate
+ * node, so we mustn't include these again.
*/
- if (aggref->aggfilter)
+ if (!context->combineStates)
{
- cost_qual_eval_node(&argcosts, (Node *) aggref->aggfilter,
- context->root);
+ /* add the input expressions' cost to per-input-row costs */
+ cost_qual_eval_node(&argcosts, (Node *) aggref->args, context->root);
costs->transCost.startup += argcosts.startup;
costs->transCost.per_tuple += argcosts.per_tuple;
+
+ /*
+ * Add any filter's cost to per-input-row costs.
+ *
+ * XXX Ideally we should reduce input expression costs according
+ * to filter selectivity, but it's not clear it's worth the
+ * trouble.
+ */
+ if (aggref->aggfilter)
+ {
+ cost_qual_eval_node(&argcosts, (Node *) aggref->aggfilter,
+ context->root);
+ costs->transCost.startup += argcosts.startup;
+ costs->transCost.per_tuple += argcosts.per_tuple;
+ }
}
/*
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 3ab57f155d..1eb1eb4a54 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -67,7 +67,8 @@ extern List *make_ands_implicit(Expr *clause);
extern PartialAggType aggregates_allow_partial(Node *clause);
extern bool contain_agg_clause(Node *clause);
extern void count_agg_clauses(PlannerInfo *root, Node *clause,
- AggClauseCosts *costs);
+ AggClauseCosts *costs, bool finalizeAggs,
+ bool combineStates, bool serialStates);
extern bool contain_window_function(Node *clause);
extern WindowFuncLists *find_window_functions(Node *clause, Index maxWinRef);