diff options
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 87 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 2 |
2 files changed, 59 insertions, 30 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index b3c2aec97b0..8b0d8623db6 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -50,6 +50,12 @@ typedef struct { + PlannerInfo *root; + AggClauseCosts *costs; +} count_agg_clauses_context; + +typedef struct +{ ParamListInfo boundParams; PlannerGlobal *glob; List *active_fns; @@ -79,7 +85,8 @@ typedef struct static bool contain_agg_clause_walker(Node *node, void *context); static bool pull_agg_clause_walker(Node *node, List **context); -static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts); +static bool count_agg_clauses_walker(Node *node, + count_agg_clauses_context *context); static bool find_window_functions_walker(Node *node, WindowFuncLists *lists); static bool expression_returns_set_rows_walker(Node *node, double *count); static bool contain_subplans_walker(Node *node, void *context); @@ -448,48 +455,80 @@ pull_agg_clause_walker(Node *node, List **context) /* * count_agg_clauses - * Recursively count the Aggref nodes in an expression tree. + * Recursively count the Aggref nodes in an expression tree, and + * accumulate other cost information about them too. * * Note: this also checks for nested aggregates, which are an error. * - * We not only count the nodes, but attempt to estimate the total space - * needed for their transition state values if all are evaluated in parallel - * (as would be done in a HashAgg plan). See AggClauseCounts for the exact - * set of statistics returned. + * We not only count the nodes, but estimate their execution costs, and + * attempt to estimate the total space needed for their transition state + * values if all are evaluated in parallel (as would be done in a HashAgg + * plan). See AggClauseCosts for the exact set of statistics collected. * - * NOTE that the counts are ADDED to those already in *counts ... so the - * caller is responsible for zeroing the struct initially. + * NOTE that the counts/costs are ADDED to those already in *costs ... so + * the caller is responsible for zeroing the struct initially. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries. There mustn't be outer-aggregate references either. */ void -count_agg_clauses(Node *clause, AggClauseCounts *counts) +count_agg_clauses(PlannerInfo *root, Node *clause, AggClauseCosts *costs) { - /* no setup needed */ - count_agg_clauses_walker(clause, counts); + count_agg_clauses_context context; + + context.root = root; + context.costs = costs; + (void) count_agg_clauses_walker(clause, &context); } static bool -count_agg_clauses_walker(Node *node, AggClauseCounts *counts) +count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) { if (node == NULL) return false; if (IsA(node, Aggref)) { Aggref *aggref = (Aggref *) node; - Oid *inputTypes; - int numArguments; + AggClauseCosts *costs = context->costs; HeapTuple aggTuple; Form_pg_aggregate aggform; + Oid aggtransfn; + Oid aggfinalfn; Oid aggtranstype; + QualCost argcosts; + Oid *inputTypes; + int numArguments; ListCell *l; Assert(aggref->agglevelsup == 0); - counts->numAggs++; + + /* fetch info about aggregate from pg_aggregate */ + aggTuple = SearchSysCache1(AGGFNOID, + ObjectIdGetDatum(aggref->aggfnoid)); + if (!HeapTupleIsValid(aggTuple)) + elog(ERROR, "cache lookup failed for aggregate %u", + aggref->aggfnoid); + aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple); + aggtransfn = aggform->aggtransfn; + aggfinalfn = aggform->aggfinalfn; + aggtranstype = aggform->aggtranstype; + ReleaseSysCache(aggTuple); + + /* count it */ + costs->numAggs++; if (aggref->aggorder != NIL || aggref->aggdistinct != NIL) - counts->numOrderedAggs++; + 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; + + /* 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; /* extract argument types (ignoring any ORDER BY expressions) */ inputTypes = (Oid *) palloc(sizeof(Oid) * list_length(aggref->args)); @@ -502,16 +541,6 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) inputTypes[numArguments++] = exprType((Node *) tle->expr); } - /* fetch aggregate transition datatype from pg_aggregate */ - aggTuple = SearchSysCache1(AGGFNOID, - ObjectIdGetDatum(aggref->aggfnoid)); - if (!HeapTupleIsValid(aggTuple)) - elog(ERROR, "cache lookup failed for aggregate %u", - aggref->aggfnoid); - aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple); - aggtranstype = aggform->aggtranstype; - ReleaseSysCache(aggTuple); - /* resolve actual type of transition state, if polymorphic */ if (IsPolymorphicType(aggtranstype)) { @@ -554,7 +583,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod); avgwidth = MAXALIGN(avgwidth); - counts->transitionSpace += avgwidth + 2 * sizeof(void *); + costs->transitionSpace += avgwidth + 2 * sizeof(void *); } else if (aggtranstype == INTERNALOID) { @@ -566,7 +595,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) * being kept in a private memory context, as is done by * array_agg() for instance. */ - counts->transitionSpace += ALLOCSET_DEFAULT_INITSIZE; + costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE; } /* @@ -585,7 +614,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, count_agg_clauses_walker, - (void *) counts); + (void *) context); } diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 55218b58694..161d5ab122e 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1103,7 +1103,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, all_hash = false; /* don't try to hash */ else cost_agg(&agg_path, root, - AGG_HASHED, 0, + AGG_HASHED, NULL, numCols, pathnode->rows, subpath->startup_cost, subpath->total_cost, |