Merge restrictlist_selectivity into clauselist_selectivity by
teaching the latter to accept either RestrictInfo nodes or bare clause expressions; and cache the selectivity result in the RestrictInfo node when possible. This extends the caching behavior of approx_selectivity to many more contexts, and should reduce duplicate selectivity calculations.
This commit is contained in:
parent
21a1202281
commit
82b4dd394f
|
@ -15,7 +15,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.271 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.272 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1170,6 +1170,7 @@ _copyRestrictInfo(RestrictInfo *from)
|
||||||
COPY_NODE_FIELD(clause);
|
COPY_NODE_FIELD(clause);
|
||||||
COPY_SCALAR_FIELD(ispusheddown);
|
COPY_SCALAR_FIELD(ispusheddown);
|
||||||
COPY_SCALAR_FIELD(canjoin);
|
COPY_SCALAR_FIELD(canjoin);
|
||||||
|
COPY_BITMAPSET_FIELD(clause_relids);
|
||||||
COPY_BITMAPSET_FIELD(left_relids);
|
COPY_BITMAPSET_FIELD(left_relids);
|
||||||
COPY_BITMAPSET_FIELD(right_relids);
|
COPY_BITMAPSET_FIELD(right_relids);
|
||||||
COPY_NODE_FIELD(orclause);
|
COPY_NODE_FIELD(orclause);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.224 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.225 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every node type that can appear in stored rules' parsetrees *must*
|
* Every node type that can appear in stored rules' parsetrees *must*
|
||||||
|
@ -1075,6 +1075,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
|
||||||
WRITE_NODE_FIELD(clause);
|
WRITE_NODE_FIELD(clause);
|
||||||
WRITE_BOOL_FIELD(ispusheddown);
|
WRITE_BOOL_FIELD(ispusheddown);
|
||||||
WRITE_BOOL_FIELD(canjoin);
|
WRITE_BOOL_FIELD(canjoin);
|
||||||
|
WRITE_BITMAPSET_FIELD(clause_relids);
|
||||||
WRITE_BITMAPSET_FIELD(left_relids);
|
WRITE_BITMAPSET_FIELD(left_relids);
|
||||||
WRITE_BITMAPSET_FIELD(right_relids);
|
WRITE_BITMAPSET_FIELD(right_relids);
|
||||||
WRITE_NODE_FIELD(orclause);
|
WRITE_NODE_FIELD(orclause);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.62 2003/12/29 21:44:49 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.63 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -54,33 +54,13 @@ static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
|
||||||
* ROUTINES TO COMPUTE SELECTIVITIES
|
* ROUTINES TO COMPUTE SELECTIVITIES
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/*
|
|
||||||
* restrictlist_selectivity -
|
|
||||||
* Compute the selectivity of an implicitly-ANDed list of RestrictInfo
|
|
||||||
* clauses.
|
|
||||||
*
|
|
||||||
* This is the same as clauselist_selectivity except for the representation
|
|
||||||
* of the clause list.
|
|
||||||
*/
|
|
||||||
Selectivity
|
|
||||||
restrictlist_selectivity(Query *root,
|
|
||||||
List *restrictinfo_list,
|
|
||||||
int varRelid,
|
|
||||||
JoinType jointype)
|
|
||||||
{
|
|
||||||
List *clauselist = get_actual_clauses(restrictinfo_list);
|
|
||||||
Selectivity result;
|
|
||||||
|
|
||||||
result = clauselist_selectivity(root, clauselist, varRelid, jointype);
|
|
||||||
freeList(clauselist);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clauselist_selectivity -
|
* clauselist_selectivity -
|
||||||
* Compute the selectivity of an implicitly-ANDed list of boolean
|
* Compute the selectivity of an implicitly-ANDed list of boolean
|
||||||
* expression clauses. The list can be empty, in which case 1.0
|
* expression clauses. The list can be empty, in which case 1.0
|
||||||
* must be returned.
|
* must be returned. List elements may be either RestrictInfos
|
||||||
|
* or bare expression clauses --- the former is preferred since
|
||||||
|
* it allows caching of results.
|
||||||
*
|
*
|
||||||
* See clause_selectivity() for the meaning of the additional parameters.
|
* See clause_selectivity() for the meaning of the additional parameters.
|
||||||
*
|
*
|
||||||
|
@ -133,64 +113,80 @@ clauselist_selectivity(Query *root,
|
||||||
foreach(clist, clauses)
|
foreach(clist, clauses)
|
||||||
{
|
{
|
||||||
Node *clause = (Node *) lfirst(clist);
|
Node *clause = (Node *) lfirst(clist);
|
||||||
|
RestrictInfo *rinfo;
|
||||||
Selectivity s2;
|
Selectivity s2;
|
||||||
|
|
||||||
|
/* Always compute the selectivity using clause_selectivity */
|
||||||
|
s2 = clause_selectivity(root, clause, varRelid, jointype);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for being passed a RestrictInfo.
|
||||||
|
*/
|
||||||
|
if (IsA(clause, RestrictInfo))
|
||||||
|
{
|
||||||
|
rinfo = (RestrictInfo *) clause;
|
||||||
|
clause = (Node *) rinfo->clause;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rinfo = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if it looks like a restriction clause with a pseudoconstant
|
* See if it looks like a restriction clause with a pseudoconstant
|
||||||
* on one side. (Anything more complicated than that might not
|
* on one side. (Anything more complicated than that might not
|
||||||
* behave in the simple way we are expecting.)
|
* behave in the simple way we are expecting.) Most of the tests
|
||||||
*
|
* here can be done more efficiently with rinfo than without.
|
||||||
* NB: for consistency of results, this fragment of code had better
|
|
||||||
* match what clause_selectivity() would do in the cases it
|
|
||||||
* handles.
|
|
||||||
*/
|
*/
|
||||||
if (is_opclause(clause) &&
|
if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2)
|
||||||
(varRelid != 0 || NumRelids(clause) == 1))
|
|
||||||
{
|
{
|
||||||
OpExpr *expr = (OpExpr *) clause;
|
OpExpr *expr = (OpExpr *) clause;
|
||||||
|
bool varonleft = true;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
if (length(expr->args) == 2)
|
if (rinfo)
|
||||||
{
|
{
|
||||||
bool varonleft = true;
|
ok = (bms_membership(rinfo->clause_relids) == BMS_SINGLETON) &&
|
||||||
|
(is_pseudo_constant_clause_relids(lsecond(expr->args),
|
||||||
|
rinfo->right_relids) ||
|
||||||
|
(varonleft = false,
|
||||||
|
is_pseudo_constant_clause_relids(lfirst(expr->args),
|
||||||
|
rinfo->left_relids)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = (NumRelids(clause) == 1) &&
|
||||||
|
(is_pseudo_constant_clause(lsecond(expr->args)) ||
|
||||||
|
(varonleft = false,
|
||||||
|
is_pseudo_constant_clause(lfirst(expr->args))));
|
||||||
|
}
|
||||||
|
|
||||||
if (is_pseudo_constant_clause(lsecond(expr->args)) ||
|
if (ok)
|
||||||
(varonleft = false,
|
{
|
||||||
is_pseudo_constant_clause(lfirst(expr->args))))
|
/*
|
||||||
|
* If it's not a "<" or ">" operator, just merge the
|
||||||
|
* selectivity in generically. But if it's the
|
||||||
|
* right oprrest, add the clause to rqlist for later
|
||||||
|
* processing.
|
||||||
|
*/
|
||||||
|
switch (get_oprrest(expr->opno))
|
||||||
{
|
{
|
||||||
Oid opno = expr->opno;
|
case F_SCALARLTSEL:
|
||||||
RegProcedure oprrest = get_oprrest(opno);
|
addRangeClause(&rqlist, clause,
|
||||||
|
varonleft, true, s2);
|
||||||
s2 = restriction_selectivity(root, opno,
|
break;
|
||||||
expr->args, varRelid);
|
case F_SCALARGTSEL:
|
||||||
|
addRangeClause(&rqlist, clause,
|
||||||
/*
|
varonleft, false, s2);
|
||||||
* If we reach here, we have computed the same result
|
break;
|
||||||
* that clause_selectivity would, so we can just use
|
default:
|
||||||
* s2 if it's the wrong oprrest. But if it's the
|
/* Just merge the selectivity in generically */
|
||||||
* right oprrest, add the clause to rqlist for later
|
s1 = s1 * s2;
|
||||||
* processing.
|
break;
|
||||||
*/
|
|
||||||
switch (oprrest)
|
|
||||||
{
|
|
||||||
case F_SCALARLTSEL:
|
|
||||||
addRangeClause(&rqlist, clause,
|
|
||||||
varonleft, true, s2);
|
|
||||||
break;
|
|
||||||
case F_SCALARGTSEL:
|
|
||||||
addRangeClause(&rqlist, clause,
|
|
||||||
varonleft, false, s2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Just merge the selectivity in generically */
|
|
||||||
s1 = s1 * s2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue; /* drop to loop bottom */
|
|
||||||
}
|
}
|
||||||
|
continue; /* drop to loop bottom */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not the right form, so treat it generically. */
|
/* Not the right form, so treat it generically. */
|
||||||
s2 = clause_selectivity(root, clause, varRelid, jointype);
|
|
||||||
s1 = s1 * s2;
|
s1 = s1 * s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +348,39 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause,
|
||||||
*rqlist = rqelem;
|
*rqlist = rqelem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bms_is_subset_singleton
|
||||||
|
*
|
||||||
|
* Same result as bms_is_subset(s, bms_make_singleton(x)),
|
||||||
|
* but a little faster and doesn't leak memory.
|
||||||
|
*
|
||||||
|
* Is this of use anywhere else? If so move to bitmapset.c ...
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
bms_is_subset_singleton(const Bitmapset *s, int x)
|
||||||
|
{
|
||||||
|
switch (bms_membership(s))
|
||||||
|
{
|
||||||
|
case BMS_EMPTY_SET:
|
||||||
|
return true;
|
||||||
|
case BMS_SINGLETON:
|
||||||
|
return bms_is_member(x, s);
|
||||||
|
case BMS_MULTIPLE:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* can't get here... */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clause_selectivity -
|
* clause_selectivity -
|
||||||
* Compute the selectivity of a general boolean expression clause.
|
* Compute the selectivity of a general boolean expression clause.
|
||||||
*
|
*
|
||||||
|
* The clause can be either a RestrictInfo or a plain expression. If it's
|
||||||
|
* a RestrictInfo, we try to cache the selectivity for possible re-use,
|
||||||
|
* so passing RestrictInfos is preferred.
|
||||||
|
*
|
||||||
* varRelid is either 0 or a rangetable index.
|
* varRelid is either 0 or a rangetable index.
|
||||||
*
|
*
|
||||||
* When varRelid is not 0, only variables belonging to that relation are
|
* When varRelid is not 0, only variables belonging to that relation are
|
||||||
|
@ -379,9 +403,37 @@ clause_selectivity(Query *root,
|
||||||
JoinType jointype)
|
JoinType jointype)
|
||||||
{
|
{
|
||||||
Selectivity s1 = 1.0; /* default for any unhandled clause type */
|
Selectivity s1 = 1.0; /* default for any unhandled clause type */
|
||||||
|
RestrictInfo *rinfo = NULL;
|
||||||
|
bool cacheable = false;
|
||||||
|
|
||||||
if (clause == NULL)
|
if (clause == NULL) /* can this still happen? */
|
||||||
return s1;
|
return s1;
|
||||||
|
|
||||||
|
if (IsA(clause, RestrictInfo))
|
||||||
|
{
|
||||||
|
rinfo = (RestrictInfo *) clause;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If possible, cache the result of the selectivity calculation for
|
||||||
|
* the clause. We can cache if varRelid is zero or the clause
|
||||||
|
* contains only vars of that relid --- otherwise varRelid will affect
|
||||||
|
* the result, so mustn't cache. We ignore the possibility that
|
||||||
|
* jointype will affect the result, which should be okay because outer
|
||||||
|
* join clauses will always be examined with the same jointype value.
|
||||||
|
*/
|
||||||
|
if (varRelid == 0 ||
|
||||||
|
bms_is_subset_singleton(rinfo->clause_relids, varRelid))
|
||||||
|
{
|
||||||
|
/* Cacheable --- do we already have the result? */
|
||||||
|
if (rinfo->this_selec >= 0)
|
||||||
|
return rinfo->this_selec;
|
||||||
|
cacheable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Proceed with examination of contained clause */
|
||||||
|
clause = (Node *) rinfo->clause;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsA(clause, Var))
|
if (IsA(clause, Var))
|
||||||
{
|
{
|
||||||
Var *var = (Var *) clause;
|
Var *var = (Var *) clause;
|
||||||
|
@ -448,9 +500,10 @@ clause_selectivity(Query *root,
|
||||||
else if (or_clause(clause))
|
else if (or_clause(clause))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Selectivities for an 'or' clause are computed as s1+s2 - s1*s2
|
* Selectivities for an OR clause are computed as s1+s2 - s1*s2
|
||||||
* to account for the probable overlap of selected tuple sets. XXX
|
* to account for the probable overlap of selected tuple sets.
|
||||||
* is this too conservative?
|
*
|
||||||
|
* XXX is this too conservative?
|
||||||
*/
|
*/
|
||||||
List *arg;
|
List *arg;
|
||||||
|
|
||||||
|
@ -483,9 +536,13 @@ clause_selectivity(Query *root,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Otherwise, it's a join if there's more than one relation
|
* Otherwise, it's a join if there's more than one relation
|
||||||
* used.
|
* used. We can optimize this calculation if an rinfo was passed.
|
||||||
*/
|
*/
|
||||||
is_join_clause = (NumRelids(clause) > 1);
|
if (rinfo)
|
||||||
|
is_join_clause = (bms_membership(rinfo->clause_relids) ==
|
||||||
|
BMS_MULTIPLE);
|
||||||
|
else
|
||||||
|
is_join_clause = (NumRelids(clause) > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_join_clause)
|
if (is_join_clause)
|
||||||
|
@ -559,6 +616,10 @@ clause_selectivity(Query *root,
|
||||||
jointype);
|
jointype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cache the result if possible */
|
||||||
|
if (cacheable)
|
||||||
|
rinfo->this_selec = s1;
|
||||||
|
|
||||||
#ifdef SELECTIVITY_DEBUG
|
#ifdef SELECTIVITY_DEBUG
|
||||||
elog(DEBUG4, "clause_selectivity: s1 %f", s1);
|
elog(DEBUG4, "clause_selectivity: s1 %f", s1);
|
||||||
#endif /* SELECTIVITY_DEBUG */
|
#endif /* SELECTIVITY_DEBUG */
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.118 2003/12/18 03:46:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.119 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1625,15 +1625,12 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||||
* The input can be either an implicitly-ANDed list of boolean
|
* The input can be either an implicitly-ANDed list of boolean
|
||||||
* expressions, or a list of RestrictInfo nodes (typically the latter).
|
* expressions, or a list of RestrictInfo nodes (typically the latter).
|
||||||
*
|
*
|
||||||
* The "quick" part comes from caching the selectivity estimates so we can
|
* This is quick-and-dirty because we bypass clauselist_selectivity, and
|
||||||
* avoid recomputing them later. (Since the same clauses are typically
|
* simply multiply the independent clause selectivities together. Now
|
||||||
* examined over and over in different possible join trees, this makes a
|
|
||||||
* big difference.)
|
|
||||||
*
|
|
||||||
* The "dirty" part comes from the fact that the selectivities of multiple
|
|
||||||
* clauses are estimated independently and multiplied together. Now
|
|
||||||
* clauselist_selectivity often can't do any better than that anyhow, but
|
* clauselist_selectivity often can't do any better than that anyhow, but
|
||||||
* for some situations (such as range constraints) it is smarter.
|
* for some situations (such as range constraints) it is smarter. However,
|
||||||
|
* we can't effectively cache the results of clauselist_selectivity, whereas
|
||||||
|
* the individual clause selectivities can be and are cached.
|
||||||
*
|
*
|
||||||
* Since we are only using the results to estimate how many potential
|
* Since we are only using the results to estimate how many potential
|
||||||
* output tuples are generated and passed through qpqual checking, it
|
* output tuples are generated and passed through qpqual checking, it
|
||||||
|
@ -1648,33 +1645,9 @@ approx_selectivity(Query *root, List *quals, JoinType jointype)
|
||||||
foreach(l, quals)
|
foreach(l, quals)
|
||||||
{
|
{
|
||||||
Node *qual = (Node *) lfirst(l);
|
Node *qual = (Node *) lfirst(l);
|
||||||
Selectivity selec;
|
|
||||||
|
|
||||||
/*
|
/* Note that clause_selectivity will be able to cache its result */
|
||||||
* RestrictInfo nodes contain a this_selec field reserved for this
|
total *= clause_selectivity(root, qual, 0, jointype);
|
||||||
* routine's use, so that it's not necessary to evaluate the qual
|
|
||||||
* clause's selectivity more than once. If the clause's
|
|
||||||
* selectivity hasn't been computed yet, the field will contain
|
|
||||||
* -1.
|
|
||||||
*/
|
|
||||||
if (qual && IsA(qual, RestrictInfo))
|
|
||||||
{
|
|
||||||
RestrictInfo *restrictinfo = (RestrictInfo *) qual;
|
|
||||||
|
|
||||||
if (restrictinfo->this_selec < 0)
|
|
||||||
restrictinfo->this_selec =
|
|
||||||
clause_selectivity(root,
|
|
||||||
(Node *) restrictinfo->clause,
|
|
||||||
0,
|
|
||||||
jointype);
|
|
||||||
selec = restrictinfo->this_selec;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If it's a bare expression, must always do it the hard way */
|
|
||||||
selec = clause_selectivity(root, qual, 0, jointype);
|
|
||||||
}
|
|
||||||
total *= selec;
|
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
@ -1702,10 +1675,10 @@ set_baserel_size_estimates(Query *root, RelOptInfo *rel)
|
||||||
Assert(rel->relid > 0);
|
Assert(rel->relid > 0);
|
||||||
|
|
||||||
temp = rel->tuples *
|
temp = rel->tuples *
|
||||||
restrictlist_selectivity(root,
|
clauselist_selectivity(root,
|
||||||
rel->baserestrictinfo,
|
rel->baserestrictinfo,
|
||||||
rel->relid,
|
0,
|
||||||
JOIN_INNER);
|
JOIN_INNER);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force estimate to be at least one row, to make explain output look
|
* Force estimate to be at least one row, to make explain output look
|
||||||
|
@ -1765,10 +1738,10 @@ set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
|
||||||
* not double-counting them because they were not considered in
|
* not double-counting them because they were not considered in
|
||||||
* estimating the sizes of the component rels.
|
* estimating the sizes of the component rels.
|
||||||
*/
|
*/
|
||||||
selec = restrictlist_selectivity(root,
|
selec = clauselist_selectivity(root,
|
||||||
restrictlist,
|
restrictlist,
|
||||||
0,
|
0,
|
||||||
jointype);
|
jointype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basically, we multiply size of Cartesian product by selectivity.
|
* Basically, we multiply size of Cartesian product by selectivity.
|
||||||
|
@ -1875,10 +1848,10 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
|
||||||
|
|
||||||
/* Now estimate number of output rows */
|
/* Now estimate number of output rows */
|
||||||
temp = rel->tuples *
|
temp = rel->tuples *
|
||||||
restrictlist_selectivity(root,
|
clauselist_selectivity(root,
|
||||||
rel->baserestrictinfo,
|
rel->baserestrictinfo,
|
||||||
rel->relid,
|
0,
|
||||||
JOIN_INNER);
|
JOIN_INNER);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force estimate to be at least one row, to make explain output look
|
* Force estimate to be at least one row, to make explain output look
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.152 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.153 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1449,7 +1449,7 @@ make_innerjoin_index_path(Query *root,
|
||||||
* the full set of clauses that must be considered to compute the
|
* the full set of clauses that must be considered to compute the
|
||||||
* correct selectivity. (Without the union operation, we might have
|
* correct selectivity. (Without the union operation, we might have
|
||||||
* some restriction clauses appearing twice, which'd mislead
|
* some restriction clauses appearing twice, which'd mislead
|
||||||
* restrictlist_selectivity into double-counting their selectivity.
|
* clauselist_selectivity into double-counting their selectivity.
|
||||||
* However, since RestrictInfo nodes aren't copied when linking them
|
* However, since RestrictInfo nodes aren't copied when linking them
|
||||||
* into different lists, it should be sufficient to use pointer
|
* into different lists, it should be sufficient to use pointer
|
||||||
* comparison to remove duplicates.)
|
* comparison to remove duplicates.)
|
||||||
|
@ -1459,10 +1459,10 @@ make_innerjoin_index_path(Query *root,
|
||||||
*/
|
*/
|
||||||
allclauses = set_ptrUnion(rel->baserestrictinfo, allclauses);
|
allclauses = set_ptrUnion(rel->baserestrictinfo, allclauses);
|
||||||
pathnode->rows = rel->tuples *
|
pathnode->rows = rel->tuples *
|
||||||
restrictlist_selectivity(root,
|
clauselist_selectivity(root,
|
||||||
allclauses,
|
allclauses,
|
||||||
rel->relid,
|
rel->relid, /* do not use 0! */
|
||||||
JOIN_INNER);
|
JOIN_INNER);
|
||||||
/* Like costsize.c, force estimate to be at least one row */
|
/* Like costsize.c, force estimate to be at least one row */
|
||||||
if (pathnode->rows < 1.0)
|
if (pathnode->rows < 1.0)
|
||||||
pathnode->rows = 1.0;
|
pathnode->rows = 1.0;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.95 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.96 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -375,15 +375,15 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
||||||
Relids qualscope)
|
Relids qualscope)
|
||||||
{
|
{
|
||||||
Relids relids;
|
Relids relids;
|
||||||
List *vars;
|
|
||||||
bool can_be_equijoin;
|
bool can_be_equijoin;
|
||||||
RestrictInfo *restrictinfo;
|
RestrictInfo *restrictinfo;
|
||||||
RelOptInfo *rel;
|
RelOptInfo *rel;
|
||||||
|
List *vars;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieve all relids and vars contained within the clause.
|
* Retrieve all relids mentioned within the clause.
|
||||||
*/
|
*/
|
||||||
clause_get_relids_vars(clause, &relids, &vars);
|
relids = pull_varnos(clause);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cross-check: clause should contain no relids not within its scope.
|
* Cross-check: clause should contain no relids not within its scope.
|
||||||
|
@ -571,7 +571,9 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
||||||
* that scan those relations (else they won't be available at
|
* that scan those relations (else they won't be available at
|
||||||
* the join node!).
|
* the join node!).
|
||||||
*/
|
*/
|
||||||
|
vars = pull_var_clause(clause, false);
|
||||||
add_vars_to_targetlist(root, vars, relids);
|
add_vars_to_targetlist(root, vars, relids);
|
||||||
|
freeList(vars);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.106 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.107 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -885,9 +885,10 @@ adjust_inherited_attrs_mutator(Node *node,
|
||||||
newinfo->orclause = (Expr *)
|
newinfo->orclause = (Expr *)
|
||||||
adjust_inherited_attrs_mutator((Node *) oldinfo->orclause, context);
|
adjust_inherited_attrs_mutator((Node *) oldinfo->orclause, context);
|
||||||
|
|
||||||
/*
|
/* adjust relid sets too */
|
||||||
* Adjust left/right relid sets too.
|
newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
|
||||||
*/
|
context->old_rt_index,
|
||||||
|
context->new_rt_index);
|
||||||
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
|
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
|
||||||
context->old_rt_index,
|
context->old_rt_index,
|
||||||
context->new_rt_index);
|
context->new_rt_index);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.158 2003/12/30 23:53:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.159 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
|
@ -928,51 +928,6 @@ has_distinct_on_clause(Query *query)
|
||||||
* *
|
* *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*
|
|
||||||
* clause_get_relids_vars
|
|
||||||
* Retrieves distinct relids and vars appearing within a clause.
|
|
||||||
*
|
|
||||||
* '*relids' is set to the set of all distinct "varno"s appearing
|
|
||||||
* in Vars within the clause.
|
|
||||||
* '*vars' is set to a list of all distinct Vars appearing within the clause.
|
|
||||||
* Var nodes are considered distinct if they have different varno
|
|
||||||
* or varattno values. If there are several occurrences of the same
|
|
||||||
* varno/varattno, you get a randomly chosen one...
|
|
||||||
*
|
|
||||||
* Note that upper-level vars are ignored, since they normally will
|
|
||||||
* become Params with respect to this query level.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
|
||||||
{
|
|
||||||
List *clvars = pull_var_clause(clause, false);
|
|
||||||
Relids varnos = NULL;
|
|
||||||
List *var_list = NIL;
|
|
||||||
List *i;
|
|
||||||
|
|
||||||
foreach(i, clvars)
|
|
||||||
{
|
|
||||||
Var *var = (Var *) lfirst(i);
|
|
||||||
List *vi;
|
|
||||||
|
|
||||||
varnos = bms_add_member(varnos, var->varno);
|
|
||||||
foreach(vi, var_list)
|
|
||||||
{
|
|
||||||
Var *in_list = (Var *) lfirst(vi);
|
|
||||||
|
|
||||||
if (in_list->varno == var->varno &&
|
|
||||||
in_list->varattno == var->varattno)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (vi == NIL)
|
|
||||||
var_list = lcons(var, var_list);
|
|
||||||
}
|
|
||||||
freeList(clvars);
|
|
||||||
|
|
||||||
*relids = varnos;
|
|
||||||
*vars = var_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NumRelids
|
* NumRelids
|
||||||
* (formerly clause_relids)
|
* (formerly clause_relids)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.22 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.23 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -47,12 +47,16 @@ make_restrictinfo(Expr *clause, bool ispusheddown)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's a binary opclause, set up left/right relids info.
|
* If it's a binary opclause, set up left/right relids info.
|
||||||
|
* In any case set up the total clause relids info.
|
||||||
*/
|
*/
|
||||||
if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2)
|
if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2)
|
||||||
{
|
{
|
||||||
restrictinfo->left_relids = pull_varnos(get_leftop(clause));
|
restrictinfo->left_relids = pull_varnos(get_leftop(clause));
|
||||||
restrictinfo->right_relids = pull_varnos(get_rightop(clause));
|
restrictinfo->right_relids = pull_varnos(get_rightop(clause));
|
||||||
|
|
||||||
|
restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
|
||||||
|
restrictinfo->right_relids);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Does it look like a normal join clause, i.e., a binary operator
|
* Does it look like a normal join clause, i.e., a binary operator
|
||||||
* relating expressions that come from distinct relations? If so
|
* relating expressions that come from distinct relations? If so
|
||||||
|
@ -67,9 +71,11 @@ make_restrictinfo(Expr *clause, bool ispusheddown)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Not a binary opclause, so mark both relid sets as empty */
|
/* Not a binary opclause, so mark left/right relid sets as empty */
|
||||||
restrictinfo->left_relids = NULL;
|
restrictinfo->left_relids = NULL;
|
||||||
restrictinfo->right_relids = NULL;
|
restrictinfo->right_relids = NULL;
|
||||||
|
/* and get the total relid set the hard way */
|
||||||
|
restrictinfo->clause_relids = pull_varnos((Node *) clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -328,9 +334,13 @@ join_clause_is_redundant(Query *root,
|
||||||
bool redundant = false;
|
bool redundant = false;
|
||||||
List *refitem;
|
List *refitem;
|
||||||
|
|
||||||
|
/* do the cheap test first: is it a "var = const" clause? */
|
||||||
|
if (bms_is_empty(rinfo->left_relids) ||
|
||||||
|
bms_is_empty(rinfo->right_relids))
|
||||||
|
return false; /* var = const, so not redundant */
|
||||||
|
|
||||||
cache_mergeclause_pathkeys(root, rinfo);
|
cache_mergeclause_pathkeys(root, rinfo);
|
||||||
|
|
||||||
/* do the cheap tests first */
|
|
||||||
foreach(refitem, reference_list)
|
foreach(refitem, reference_list)
|
||||||
{
|
{
|
||||||
RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
|
RestrictInfo *refrinfo = (RestrictInfo *) lfirst(refitem);
|
||||||
|
@ -347,13 +357,7 @@ join_clause_is_redundant(Query *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redundant)
|
if (redundant)
|
||||||
{
|
return true; /* var = var, so redundant */
|
||||||
/* It looks redundant, but check for "var = const" case */
|
|
||||||
if (!bms_is_empty(rinfo->left_relids) &&
|
|
||||||
!bms_is_empty(rinfo->right_relids))
|
|
||||||
return true; /* var = var, so redundant */
|
|
||||||
/* else var = const, not redundant */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise, not redundant */
|
/* otherwise, not redundant */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.89 2004/01/04 00:07:32 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.90 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -613,6 +613,9 @@ typedef struct RestrictInfo
|
||||||
*/
|
*/
|
||||||
bool canjoin;
|
bool canjoin;
|
||||||
|
|
||||||
|
/* The set of relids (varnos) referenced in the clause: */
|
||||||
|
Relids clause_relids;
|
||||||
|
|
||||||
/* These fields are set for any binary opclause: */
|
/* These fields are set for any binary opclause: */
|
||||||
Relids left_relids; /* relids in left side of clause */
|
Relids left_relids; /* relids in left side of clause */
|
||||||
Relids right_relids; /* relids in right side of clause */
|
Relids right_relids; /* relids in right side of clause */
|
||||||
|
@ -620,7 +623,7 @@ typedef struct RestrictInfo
|
||||||
/* This field is NULL unless clause is an OR clause: */
|
/* This field is NULL unless clause is an OR clause: */
|
||||||
Expr *orclause; /* modified clause with RestrictInfos */
|
Expr *orclause; /* modified clause with RestrictInfos */
|
||||||
|
|
||||||
/* cache space for costs (currently only used for join clauses) */
|
/* cache space for cost and selectivity */
|
||||||
QualCost eval_cost; /* eval cost of clause; -1 if not yet set */
|
QualCost eval_cost; /* eval cost of clause; -1 if not yet set */
|
||||||
Selectivity this_selec; /* selectivity; -1 if not yet set */
|
Selectivity this_selec; /* selectivity; -1 if not yet set */
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.70 2003/12/30 23:53:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.71 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -59,7 +59,6 @@ extern List *pull_constant_clauses(List *quals, List **constantQual);
|
||||||
|
|
||||||
extern bool has_distinct_on_clause(Query *query);
|
extern bool has_distinct_on_clause(Query *query);
|
||||||
|
|
||||||
extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
|
|
||||||
extern int NumRelids(Node *clause);
|
extern int NumRelids(Node *clause);
|
||||||
extern void CommuteClause(OpExpr *clause);
|
extern void CommuteClause(OpExpr *clause);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.58 2003/11/29 22:41:07 pgsql Exp $
|
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.59 2004/01/04 03:51:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -88,10 +88,6 @@ extern void set_function_size_estimates(Query *root, RelOptInfo *rel);
|
||||||
* prototypes for clausesel.c
|
* prototypes for clausesel.c
|
||||||
* routines to compute clause selectivities
|
* routines to compute clause selectivities
|
||||||
*/
|
*/
|
||||||
extern Selectivity restrictlist_selectivity(Query *root,
|
|
||||||
List *restrictinfo_list,
|
|
||||||
int varRelid,
|
|
||||||
JoinType jointype);
|
|
||||||
extern Selectivity clauselist_selectivity(Query *root,
|
extern Selectivity clauselist_selectivity(Query *root,
|
||||||
List *clauses,
|
List *clauses,
|
||||||
int varRelid,
|
int varRelid,
|
||||||
|
|
Loading…
Reference in New Issue