Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 835bb97

Browse files
committed
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.
1 parent cf883ea commit 835bb97

File tree

16 files changed

+333
-220
lines changed

16 files changed

+333
-220
lines changed

src/backend/nodes/bitmapset.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Copyright (c) 2003, PostgreSQL Global Development Group
1515
*
1616
* IDENTIFICATION
17-
* $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.1 2003/02/08 20:20:53 tgl Exp $
17+
* $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.2 2003/06/29 23:05:04 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -388,6 +388,36 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
388388
return false;
389389
}
390390

391+
/*
392+
* bms_nonempty_difference - do sets have a nonempty difference?
393+
*/
394+
bool
395+
bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
396+
{
397+
int shortlen;
398+
int i;
399+
400+
/* Handle cases where either input is NULL */
401+
if (a == NULL)
402+
return false;
403+
if (b == NULL)
404+
return !bms_is_empty(a);
405+
/* Check words in common */
406+
shortlen = Min(a->nwords, b->nwords);
407+
for (i = 0; i < shortlen; i++)
408+
{
409+
if ((a->words[i] & ~ b->words[i]) != 0)
410+
return true;
411+
}
412+
/* Check extra words in a */
413+
for (; i < a->nwords; i++)
414+
{
415+
if (a->words[i] != 0)
416+
return true;
417+
}
418+
return false;
419+
}
420+
391421
/*
392422
* bms_singleton_member - return the sole integer member of set
393423
*

src/backend/optimizer/path/allpaths.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.102 2003/04/24 23:43:09 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.103 2003/06/29 23:05:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -235,6 +235,9 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
235235
RangeTblEntry *childrte;
236236
Oid childOID;
237237
RelOptInfo *childrel;
238+
List *reltlist;
239+
List *parentvars;
240+
List *childvars;
238241

239242
childrte = rt_fetch(childRTindex, root->rtable);
240243
childOID = childrte->relid;
@@ -251,21 +254,24 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
251254
* Copy the parent's targetlist and restriction quals to the
252255
* child, with attribute-number adjustment as needed. We don't
253256
* bother to copy the join quals, since we can't do any joining of
254-
* the individual tables.
257+
* the individual tables. Also, we just zap attr_needed rather
258+
* than trying to adjust it; it won't be looked at in the child.
255259
*/
256-
childrel->targetlist = (List *)
257-
adjust_inherited_attrs((Node *) rel->targetlist,
260+
reltlist = FastListValue(&rel->reltargetlist);
261+
reltlist = (List *)
262+
adjust_inherited_attrs((Node *) reltlist,
258263
parentRTindex,
259264
parentOID,
260265
childRTindex,
261266
childOID);
267+
FastListFromList(&childrel->reltargetlist, reltlist);
268+
childrel->attr_needed = NULL;
262269
childrel->baserestrictinfo = (List *)
263270
adjust_inherited_attrs((Node *) rel->baserestrictinfo,
264271
parentRTindex,
265272
parentOID,
266273
childRTindex,
267274
childOID);
268-
childrel->baserestrictcost = rel->baserestrictcost;
269275

270276
/*
271277
* Now compute child access paths, and save the cheapest.
@@ -274,10 +280,27 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
274280

275281
subpaths = lappend(subpaths, childrel->cheapest_total_path);
276282

277-
/* Also update total size estimates */
283+
/*
284+
* Propagate size information from the child back to the parent.
285+
* For simplicity, we use the largest widths from any child as the
286+
* parent estimates.
287+
*/
278288
rel->rows += childrel->rows;
279289
if (childrel->width > rel->width)
280290
rel->width = childrel->width;
291+
292+
childvars = FastListValue(&childrel->reltargetlist);
293+
foreach(parentvars, FastListValue(&rel->reltargetlist))
294+
{
295+
Var *parentvar = (Var *) lfirst(parentvars);
296+
Var *childvar = (Var *) lfirst(childvars);
297+
int parentndx = parentvar->varattno - rel->min_attr;
298+
int childndx = childvar->varattno - childrel->min_attr;
299+
300+
if (childrel->attr_widths[childndx] > rel->attr_widths[parentndx])
301+
rel->attr_widths[parentndx] = childrel->attr_widths[childndx];
302+
childvars = lnext(childvars);
303+
}
281304
}
282305

283306
/*

src/backend/optimizer/path/costsize.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1994, Regents of the University of California
5050
*
5151
* IDENTIFICATION
52-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.108 2003/06/29 00:33:43 tgl Exp $
52+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.109 2003/06/29 23:05:04 tgl Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -1792,13 +1792,9 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
17921792
rel->rows = temp;
17931793

17941794
/*
1795-
* We could apply set_rel_width() to compute the output tuple width
1796-
* from scratch, but at present it's always just the sum of the input
1797-
* widths, so why work harder than necessary? If relnode.c is ever
1798-
* taught to remove unneeded columns from join targetlists, go back to
1799-
* using set_rel_width here.
1795+
* We need not compute the output width here, because build_joinrel_tlist
1796+
* already did.
18001797
*/
1801-
rel->width = outer_rel->width + inner_rel->width;
18021798
}
18031799

18041800
/*
@@ -1858,52 +1854,58 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
18581854

18591855
/*
18601856
* set_rel_width
1861-
* Set the estimated output width of the relation.
1857+
* Set the estimated output width of a base relation.
18621858
*
1863-
* NB: this works best on base relations because it prefers to look at
1859+
* NB: this works best on plain relations because it prefers to look at
18641860
* real Vars. It will fail to make use of pg_statistic info when applied
18651861
* to a subquery relation, even if the subquery outputs are simple vars
18661862
* that we could have gotten info for. Is it worth trying to be smarter
18671863
* about subqueries?
1864+
*
1865+
* The per-attribute width estimates are cached for possible re-use while
1866+
* building join relations.
18681867
*/
18691868
static void
18701869
set_rel_width(Query *root, RelOptInfo *rel)
18711870
{
18721871
int32 tuple_width = 0;
18731872
List *tllist;
18741873

1875-
foreach(tllist, rel->targetlist)
1874+
foreach(tllist, FastListValue(&rel->reltargetlist))
18761875
{
1877-
TargetEntry *tle = (TargetEntry *) lfirst(tllist);
1876+
Var *var = (Var *) lfirst(tllist);
1877+
int ndx = var->varattno - rel->min_attr;
1878+
Oid relid;
18781879
int32 item_width;
18791880

1880-
/*
1881-
* If it's a Var, try to get statistical info from pg_statistic.
1882-
*/
1883-
if (tle->expr && IsA(tle->expr, Var))
1881+
Assert(IsA(var, Var));
1882+
1883+
/* The width probably hasn't been cached yet, but may as well check */
1884+
if (rel->attr_widths[ndx] > 0)
18841885
{
1885-
Var *var = (Var *) tle->expr;
1886-
Oid relid;
1886+
tuple_width += rel->attr_widths[ndx];
1887+
continue;
1888+
}
18871889

1888-
relid = getrelid(var->varno, root->rtable);
1889-
if (relid != InvalidOid)
1890+
relid = getrelid(var->varno, root->rtable);
1891+
if (relid != InvalidOid)
1892+
{
1893+
item_width = get_attavgwidth(relid, var->varattno);
1894+
if (item_width > 0)
18901895
{
1891-
item_width = get_attavgwidth(relid, var->varattno);
1892-
if (item_width > 0)
1893-
{
1894-
tuple_width += item_width;
1895-
continue;
1896-
}
1896+
rel->attr_widths[ndx] = item_width;
1897+
tuple_width += item_width;
1898+
continue;
18971899
}
18981900
}
18991901

19001902
/*
1901-
* Not a Var, or can't find statistics for it. Estimate using
1902-
* just the type info.
1903+
* Not a plain relation, or can't find statistics for it.
1904+
* Estimate using just the type info.
19031905
*/
1904-
item_width = get_typavgwidth(tle->resdom->restype,
1905-
tle->resdom->restypmod);
1906+
item_width = get_typavgwidth(var->vartype, var->vartypmod);
19061907
Assert(item_width > 0);
1908+
rel->attr_widths[ndx] = item_width;
19071909
tuple_width += item_width;
19081910
}
19091911
Assert(tuple_width >= 0);

src/backend/optimizer/path/pathkeys.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.49 2003/05/28 16:03:56 tgl Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.50 2003/06/29 23:05:04 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -703,20 +703,18 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
703703
vartypeid;
704704
int32 type_mod;
705705

706-
foreach(temp, rel->targetlist)
706+
foreach(temp, FastListValue(&rel->reltargetlist))
707707
{
708-
Var *tle_var = (Var *) ((TargetEntry *) lfirst(temp))->expr;
708+
Var *var = (Var *) lfirst(temp);
709709

710-
if (IsA(tle_var, Var) &&
711-
tle_var->varattno == varattno)
712-
return tle_var;
710+
if (IsA(var, Var) &&
711+
var->varattno == varattno)
712+
return var;
713713
}
714714

715715
relid = rel->relid;
716-
Assert(relid > 0);
717716
reloid = getrelid(relid, root->rtable);
718-
vartypeid = get_atttype(reloid, varattno);
719-
type_mod = get_atttypmod(reloid, varattno);
717+
get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
720718

721719
return makeVar(relid, varattno, vartypeid, type_mod, 0);
722720
}

0 commit comments

Comments
 (0)