1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Restructure building of join relation targetlists so that a join plan

node emits only those vars that are actually needed above it in the
plan tree.  (There were comments in the code suggesting that this was
done at some point in the dim past, but for a long time we have just
made join nodes emit everything that either input emitted.)  Aside from
being marginally more efficient, this fixes the problem noted by Peter
Eisentraut where a join above an IN-implemented-as-join might fail,
because the subplan targetlist constructed in the latter case didn't
meet the expectation of including everything.
Along the way, fix some places that were O(N^2) in the targetlist
length.  This is not all the trouble spots for wide queries by any
means, but it's a step forward.
This commit is contained in:
Tom Lane
2003-06-29 23:05:05 +00:00
parent cf883ea95c
commit 835bb975d8
16 changed files with 334 additions and 221 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.102 2003/04/24 23:43:09 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.103 2003/06/29 23:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -235,6 +235,9 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
RangeTblEntry *childrte;
Oid childOID;
RelOptInfo *childrel;
List *reltlist;
List *parentvars;
List *childvars;
childrte = rt_fetch(childRTindex, root->rtable);
childOID = childrte->relid;
@ -251,21 +254,24 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
* Copy the parent's targetlist and restriction quals to the
* child, with attribute-number adjustment as needed. We don't
* bother to copy the join quals, since we can't do any joining of
* the individual tables.
* the individual tables. Also, we just zap attr_needed rather
* than trying to adjust it; it won't be looked at in the child.
*/
childrel->targetlist = (List *)
adjust_inherited_attrs((Node *) rel->targetlist,
reltlist = FastListValue(&rel->reltargetlist);
reltlist = (List *)
adjust_inherited_attrs((Node *) reltlist,
parentRTindex,
parentOID,
childRTindex,
childOID);
FastListFromList(&childrel->reltargetlist, reltlist);
childrel->attr_needed = NULL;
childrel->baserestrictinfo = (List *)
adjust_inherited_attrs((Node *) rel->baserestrictinfo,
parentRTindex,
parentOID,
childRTindex,
childOID);
childrel->baserestrictcost = rel->baserestrictcost;
/*
* Now compute child access paths, and save the cheapest.
@ -274,10 +280,27 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
subpaths = lappend(subpaths, childrel->cheapest_total_path);
/* Also update total size estimates */
/*
* Propagate size information from the child back to the parent.
* For simplicity, we use the largest widths from any child as the
* parent estimates.
*/
rel->rows += childrel->rows;
if (childrel->width > rel->width)
rel->width = childrel->width;
childvars = FastListValue(&childrel->reltargetlist);
foreach(parentvars, FastListValue(&rel->reltargetlist))
{
Var *parentvar = (Var *) lfirst(parentvars);
Var *childvar = (Var *) lfirst(childvars);
int parentndx = parentvar->varattno - rel->min_attr;
int childndx = childvar->varattno - childrel->min_attr;
if (childrel->attr_widths[childndx] > rel->attr_widths[parentndx])
rel->attr_widths[parentndx] = childrel->attr_widths[childndx];
childvars = lnext(childvars);
}
}
/*

View File

@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.108 2003/06/29 00:33:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.109 2003/06/29 23:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1792,13 +1792,9 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
rel->rows = temp;
/*
* We could apply set_rel_width() to compute the output tuple width
* from scratch, but at present it's always just the sum of the input
* widths, so why work harder than necessary? If relnode.c is ever
* taught to remove unneeded columns from join targetlists, go back to
* using set_rel_width here.
* We need not compute the output width here, because build_joinrel_tlist
* already did.
*/
rel->width = outer_rel->width + inner_rel->width;
}
/*
@ -1858,13 +1854,16 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
/*
* set_rel_width
* Set the estimated output width of the relation.
* Set the estimated output width of a base relation.
*
* NB: this works best on base relations because it prefers to look at
* NB: this works best on plain relations because it prefers to look at
* real Vars. It will fail to make use of pg_statistic info when applied
* to a subquery relation, even if the subquery outputs are simple vars
* that we could have gotten info for. Is it worth trying to be smarter
* about subqueries?
*
* The per-attribute width estimates are cached for possible re-use while
* building join relations.
*/
static void
set_rel_width(Query *root, RelOptInfo *rel)
@ -1872,38 +1871,41 @@ set_rel_width(Query *root, RelOptInfo *rel)
int32 tuple_width = 0;
List *tllist;
foreach(tllist, rel->targetlist)
foreach(tllist, FastListValue(&rel->reltargetlist))
{
TargetEntry *tle = (TargetEntry *) lfirst(tllist);
Var *var = (Var *) lfirst(tllist);
int ndx = var->varattno - rel->min_attr;
Oid relid;
int32 item_width;
/*
* If it's a Var, try to get statistical info from pg_statistic.
*/
if (tle->expr && IsA(tle->expr, Var))
{
Var *var = (Var *) tle->expr;
Oid relid;
Assert(IsA(var, Var));
relid = getrelid(var->varno, root->rtable);
if (relid != InvalidOid)
/* The width probably hasn't been cached yet, but may as well check */
if (rel->attr_widths[ndx] > 0)
{
tuple_width += rel->attr_widths[ndx];
continue;
}
relid = getrelid(var->varno, root->rtable);
if (relid != InvalidOid)
{
item_width = get_attavgwidth(relid, var->varattno);
if (item_width > 0)
{
item_width = get_attavgwidth(relid, var->varattno);
if (item_width > 0)
{
tuple_width += item_width;
continue;
}
rel->attr_widths[ndx] = item_width;
tuple_width += item_width;
continue;
}
}
/*
* Not a Var, or can't find statistics for it. Estimate using
* just the type info.
* Not a plain relation, or can't find statistics for it.
* Estimate using just the type info.
*/
item_width = get_typavgwidth(tle->resdom->restype,
tle->resdom->restypmod);
item_width = get_typavgwidth(var->vartype, var->vartypmod);
Assert(item_width > 0);
rel->attr_widths[ndx] = item_width;
tuple_width += item_width;
}
Assert(tuple_width >= 0);

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.49 2003/05/28 16:03:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.50 2003/06/29 23:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -703,20 +703,18 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
vartypeid;
int32 type_mod;
foreach(temp, rel->targetlist)
foreach(temp, FastListValue(&rel->reltargetlist))
{
Var *tle_var = (Var *) ((TargetEntry *) lfirst(temp))->expr;
Var *var = (Var *) lfirst(temp);
if (IsA(tle_var, Var) &&
tle_var->varattno == varattno)
return tle_var;
if (IsA(var, Var) &&
var->varattno == varattno)
return var;
}
relid = rel->relid;
Assert(relid > 0);
reloid = getrelid(relid, root->rtable);
vartypeid = get_atttype(reloid, varattno);
type_mod = get_atttypmod(reloid, varattno);
get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
return makeVar(relid, varattno, vartypeid, type_mod, 0);
}