summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
authorTom Lane2013-11-16 21:03:40 +0000
committerTom Lane2013-11-16 21:03:40 +0000
commit6cb86143e8e1e855255edc706bce71c6ebfd9a6c (patch)
tree2ed7cf0b5fe28b8ba858ae3e384534cdb7f31aa3 /src/backend/optimizer/util/clauses.c
parent55c3d86a2a374f9d8fd88fd947601c1f49a4da08 (diff)
Allow aggregates to provide estimates of their transition state data size.
Formerly the planner had a hard-wired rule of thumb for guessing the amount of space consumed by an aggregate function's transition state data. This estimate is critical to deciding whether it's OK to use hash aggregation, and in many situations the built-in estimate isn't very good. This patch adds a column to pg_aggregate wherein a per-aggregate estimate can be provided, overriding the planner's default, and infrastructure for setting the column via CREATE AGGREGATE. It may be that additional smarts will be required in future, perhaps even a per-aggregate estimation function. But this is already a step forward. This is extracted from a larger patch to improve the performance of numeric and int8 aggregates. I (tgl) thought it was worth reviewing and committing this infrastructure separately. In this commit, all built-in aggregates are given aggtransspace = 0, so no behavior should change. Hadi Moshayedi, reviewed by Pavel Stehule and Tomas Vondra
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index add29f54d09..7ce8a9d8180 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -461,6 +461,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
+ int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
@@ -478,6 +479,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
+ aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
@@ -541,22 +543,30 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
*/
if (!get_typbyval(aggtranstype))
{
- int32 aggtranstypmod;
int32 avgwidth;
- /*
- * If transition state is of same type as first input, assume it's
- * the same typmod (same width) as well. This works for cases
- * like MAX/MIN and is probably somewhat reasonable otherwise.
- */
- if (numArguments > 0 && aggtranstype == inputTypes[0])
- aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
+ /* Use average width if aggregate definition gave one */
+ if (aggtransspace > 0)
+ avgwidth = aggtransspace;
else
- aggtranstypmod = -1;
+ {
+ /*
+ * If transition state is of same type as first input, assume
+ * it's the same typmod (same width) as well. This works for
+ * cases like MAX/MIN and is probably somewhat reasonable
+ * otherwise.
+ */
+ int32 aggtranstypmod;
- avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);
- avgwidth = MAXALIGN(avgwidth);
+ if (numArguments > 0 && aggtranstype == inputTypes[0])
+ aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
+ else
+ aggtranstypmod = -1;
+
+ avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);
+ }
+ avgwidth = MAXALIGN(avgwidth);
costs->transitionSpace += avgwidth + 2 * sizeof(void *);
}
else if (aggtranstype == INTERNALOID)
@@ -564,12 +574,16 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
/*
* INTERNAL transition type is a special case: although INTERNAL
* is pass-by-value, it's almost certainly being used as a pointer
- * to some large data structure. We assume usage of
+ * to some large data structure. The aggregate definition can
+ * provide an estimate of the size. If it doesn't, then we assume
* ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
* being kept in a private memory context, as is done by
* array_agg() for instance.
*/
- costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
+ if (aggtransspace > 0)
+ costs->transitionSpace += aggtransspace;
+ else
+ costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
}
/*