*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.170 2008/04/01 00:48:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.171 2008/06/27 03:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include <math.h>
+
#ifdef OPTIMIZER_DEBUG
#include "nodes/print.h"
#endif
{
int parentRTindex = rti;
List *subpaths = NIL;
+ double parent_rows;
+ double parent_size;
+ double *parent_attrsizes;
+ int nattrs;
ListCell *l;
/*
errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
/*
- * Initialize to compute size estimates for whole append relation
+ * Initialize to compute size estimates for whole append relation.
+ *
+ * We handle width estimates by weighting the widths of different
+ * child rels proportionally to their number of rows. This is sensible
+ * because the use of width estimates is mainly to compute the total
+ * relation "footprint" if we have to sort or hash it. To do this,
+ * we sum the total equivalent size (in "double" arithmetic) and then
+ * divide by the total rowcount estimate. This is done separately for
+ * the total rel width and each attribute.
+ *
+ * Note: if you consider changing this logic, beware that child rels could
+ * have zero rows and/or width, if they were excluded by constraints.
*/
- rel->rows = 0;
- rel->width = 0;
+ parent_rows = 0;
+ parent_size = 0;
+ nattrs = rel->max_attr - rel->min_attr + 1;
+ parent_attrsizes = (double *) palloc0(nattrs * sizeof(double));
/*
* Generate access paths for each member relation, and pick the cheapest
subpaths = lappend(subpaths, childpath);
/*
- * Propagate size information from the child back to the parent. For
- * simplicity, we use the largest widths from any child as the parent
- * estimates. (If you want to change this, beware of child
- * attr_widths[] entries that haven't been set and are still 0.)
+ * Accumulate size information from each child.
*/
- rel->rows += childrel->rows;
- if (childrel->width > rel->width)
- rel->width = childrel->width;
-
- forboth(parentvars, rel->reltargetlist,
- childvars, childrel->reltargetlist)
+ if (childrel->rows > 0)
{
- Var *parentvar = (Var *) lfirst(parentvars);
- Var *childvar = (Var *) lfirst(childvars);
+ parent_rows += childrel->rows;
+ parent_size += childrel->width * childrel->rows;
- if (IsA(parentvar, Var) &&
- IsA(childvar, Var))
+ forboth(parentvars, rel->reltargetlist,
+ childvars, childrel->reltargetlist)
{
- int pndx = parentvar->varattno - rel->min_attr;
- int cndx = childvar->varattno - childrel->min_attr;
+ Var *parentvar = (Var *) lfirst(parentvars);
+ Var *childvar = (Var *) lfirst(childvars);
- if (childrel->attr_widths[cndx] > rel->attr_widths[pndx])
- rel->attr_widths[pndx] = childrel->attr_widths[cndx];
+ if (IsA(parentvar, Var) &&
+ IsA(childvar, Var))
+ {
+ int pndx = parentvar->varattno - rel->min_attr;
+ int cndx = childvar->varattno - childrel->min_attr;
+
+ parent_attrsizes[pndx] += childrel->attr_widths[cndx] * childrel->rows;
+ }
}
}
}
+ /*
+ * Save the finished size estimates.
+ */
+ rel->rows = parent_rows;
+ if (parent_rows > 0)
+ {
+ int i;
+
+ rel->width = rint(parent_size / parent_rows);
+ for (i = 0; i < nattrs; i++)
+ rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows);
+ }
+ else
+ rel->width = 0; /* attr_widths should be zero already */
+
/*
* Set "raw tuples" count equal to "rows" for the appendrel; needed
* because some places assume rel->tuples is valid for any baserel.
*/
- rel->tuples = rel->rows;
+ rel->tuples = parent_rows;
+
+ pfree(parent_attrsizes);
/*
* Finally, build Append path and install it as the only access path for
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.240 2008/04/17 21:22:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.241 2008/06/27 03:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <limits.h>
+#include <math.h>
#include "access/skey.h"
#include "nodes/makefuncs.h"
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
+ double total_size;
ListCell *subnode;
/*
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
- plan->plan_width = 0;
+ total_size = 0;
foreach(subnode, appendplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
plan->startup_cost = subplan->startup_cost;
plan->total_cost += subplan->total_cost;
plan->plan_rows += subplan->plan_rows;
- if (plan->plan_width < subplan->plan_width)
- plan->plan_width = subplan->plan_width;
+ total_size += subplan->plan_width * subplan->plan_rows;
}
+ if (plan->plan_rows > 0)
+ plan->plan_width = rint(total_size / plan->plan_rows);
+ else
+ plan->plan_width = 0;
plan->targetlist = tlist;
plan->qual = NIL;