mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Further work on planning of indexscans. Cleaned up interfaces
to index_selectivity so that it can be handed an indexqual clause list rather than a bunch of assorted derivative data.
This commit is contained in:
parent
8ae29a1d40
commit
49ed4dd779
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.24 1999/07/24 23:21:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.25 1999/07/25 23:07:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -142,8 +142,8 @@ compute_clause_selec(Query *root, Node *clause)
|
|||||||
BooleanEqualOperator,
|
BooleanEqualOperator,
|
||||||
relid,
|
relid,
|
||||||
((Var *) clause)->varoattno,
|
((Var *) clause)->varoattno,
|
||||||
"t",
|
Int8GetDatum(true),
|
||||||
_SELEC_CONSTANT_RIGHT_);
|
SEL_CONSTANT | SEL_RIGHT);
|
||||||
}
|
}
|
||||||
else if (IsA(clause, Param))
|
else if (IsA(clause, Param))
|
||||||
{
|
{
|
||||||
@ -215,14 +215,6 @@ compute_clause_selec(Query *root, Node *clause)
|
|||||||
*/
|
*/
|
||||||
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||||
RegProcedure oprrest = get_oprrest(opno);
|
RegProcedure oprrest = get_oprrest(opno);
|
||||||
Oid relid;
|
|
||||||
int relidx;
|
|
||||||
AttrNumber attno;
|
|
||||||
Datum constval;
|
|
||||||
int flag;
|
|
||||||
|
|
||||||
get_relattval(clause, &relidx, &attno, &constval, &flag);
|
|
||||||
relid = getrelid(relidx, root->rtable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the oprrest procedure is missing for whatever reason, use a
|
* if the oprrest procedure is missing for whatever reason, use a
|
||||||
@ -230,23 +222,34 @@ compute_clause_selec(Query *root, Node *clause)
|
|||||||
*/
|
*/
|
||||||
if (!oprrest)
|
if (!oprrest)
|
||||||
s1 = (Cost) 0.5;
|
s1 = (Cost) 0.5;
|
||||||
else if (attno == InvalidAttrNumber)
|
else
|
||||||
|
{
|
||||||
|
int relidx;
|
||||||
|
AttrNumber attno;
|
||||||
|
Datum constval;
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
get_relattval(clause, 0, &relidx, &attno, &constval, &flag);
|
||||||
|
if (relidx <= 0 || attno <= 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* attno can be Invalid if the clause had a function in it,
|
* attno can be Invalid if the clause had a function in it,
|
||||||
* i.e. WHERE myFunc(f) = 10
|
* i.e. WHERE myFunc(f) = 10
|
||||||
|
*
|
||||||
|
* XXX should be FIXED to use function selectivity
|
||||||
*/
|
*/
|
||||||
/* this should be FIXED somehow to use function selectivity */
|
|
||||||
s1 = (Cost) (0.5);
|
s1 = (Cost) (0.5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
s1 = (Cost) restriction_selectivity(oprrest,
|
s1 = (Cost) restriction_selectivity(oprrest,
|
||||||
opno,
|
opno,
|
||||||
relid,
|
getrelid(relidx,
|
||||||
|
root->rtable),
|
||||||
attno,
|
attno,
|
||||||
(char *) constval,
|
constval,
|
||||||
flag);
|
flag);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -256,14 +259,6 @@ compute_clause_selec(Query *root, Node *clause)
|
|||||||
*/
|
*/
|
||||||
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||||
RegProcedure oprjoin = get_oprjoin(opno);
|
RegProcedure oprjoin = get_oprjoin(opno);
|
||||||
int relid1,
|
|
||||||
relid2;
|
|
||||||
AttrNumber attno1,
|
|
||||||
attno2;
|
|
||||||
|
|
||||||
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
|
|
||||||
relid1 = getrelid(relid1, root->rtable);
|
|
||||||
relid2 = getrelid(relid2, root->rtable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the oprjoin procedure is missing for whatever reason, use a
|
* if the oprjoin procedure is missing for whatever reason, use a
|
||||||
@ -272,12 +267,25 @@ compute_clause_selec(Query *root, Node *clause)
|
|||||||
if (!oprjoin)
|
if (!oprjoin)
|
||||||
s1 = (Cost) (0.5);
|
s1 = (Cost) (0.5);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
int relid1,
|
||||||
|
relid2;
|
||||||
|
AttrNumber attno1,
|
||||||
|
attno2;
|
||||||
|
|
||||||
|
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
|
||||||
|
if (relid1 > 0 && relid2 > 0 && attno1 > 0 && attno2 > 0)
|
||||||
s1 = (Cost) join_selectivity(oprjoin,
|
s1 = (Cost) join_selectivity(oprjoin,
|
||||||
opno,
|
opno,
|
||||||
relid1,
|
getrelid(relid1,
|
||||||
|
root->rtable),
|
||||||
attno1,
|
attno1,
|
||||||
relid2,
|
getrelid(relid2,
|
||||||
|
root->rtable),
|
||||||
attno2);
|
attno2);
|
||||||
|
else /* XXX more code for function selectivity? */
|
||||||
|
s1 = (Cost) (0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.64 1999/07/25 17:53:27 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.65 1999/07/25 23:07:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1216,25 +1216,20 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
|||||||
{
|
{
|
||||||
List *clausegroup = lfirst(i);
|
List *clausegroup = lfirst(i);
|
||||||
IndexPath *pathnode = makeNode(IndexPath);
|
IndexPath *pathnode = makeNode(IndexPath);
|
||||||
Cost temp_selec;
|
List *indexquals;
|
||||||
float temp_pages;
|
float npages;
|
||||||
List *attnos,
|
float selec;
|
||||||
*values,
|
|
||||||
*flags;
|
|
||||||
|
|
||||||
get_joinvars(lfirsti(rel->relids), clausegroup,
|
indexquals = get_actual_clauses(clausegroup);
|
||||||
&attnos, &values, &flags);
|
|
||||||
index_selectivity(lfirsti(index->relids),
|
index_selectivity(root,
|
||||||
index->classlist,
|
lfirsti(rel->relids),
|
||||||
get_opnos(clausegroup),
|
lfirsti(index->relids),
|
||||||
getrelid(lfirsti(rel->relids),
|
indexquals,
|
||||||
root->rtable),
|
&npages,
|
||||||
attnos,
|
&selec);
|
||||||
values,
|
|
||||||
flags,
|
/* XXX this code ought to be merged with create_index_path */
|
||||||
length(clausegroup),
|
|
||||||
&temp_pages,
|
|
||||||
&temp_selec);
|
|
||||||
|
|
||||||
pathnode->path.pathtype = T_IndexScan;
|
pathnode->path.pathtype = T_IndexScan;
|
||||||
pathnode->path.parent = rel;
|
pathnode->path.parent = rel;
|
||||||
@ -1249,14 +1244,14 @@ index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
|||||||
*/
|
*/
|
||||||
pathnode->indexid = index->relids;
|
pathnode->indexid = index->relids;
|
||||||
pathnode->indexkeys = index->indexkeys;
|
pathnode->indexkeys = index->indexkeys;
|
||||||
pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
|
pathnode->indexqual = lcons(indexquals, NIL);
|
||||||
|
|
||||||
/* joinid saves the rels needed on the outer side of the join */
|
/* joinid saves the rels needed on the outer side of the join */
|
||||||
pathnode->path.joinid = lfirst(outerrelids_list);
|
pathnode->path.joinid = lfirst(outerrelids_list);
|
||||||
|
|
||||||
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
|
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
|
||||||
(int) temp_pages,
|
(int) npages,
|
||||||
temp_selec,
|
selec,
|
||||||
rel->pages,
|
rel->pages,
|
||||||
rel->tuples,
|
rel->tuples,
|
||||||
index->pages,
|
index->pages,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.29 1999/07/24 23:21:10 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.30 1999/07/25 23:07:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -121,11 +121,14 @@ create_or_index_paths(Query *root,
|
|||||||
pathnode->indexqual = NIL;
|
pathnode->indexqual = NIL;
|
||||||
foreach(orclause, clausenode->clause->args)
|
foreach(orclause, clausenode->clause->args)
|
||||||
{
|
{
|
||||||
|
Expr *subclause = (Expr *) lfirst(orclause);
|
||||||
List *sublist;
|
List *sublist;
|
||||||
if (and_clause(lfirst(orclause)))
|
|
||||||
sublist = ((Expr *) lfirst(orclause))->args;
|
if (and_clause((Node *) subclause))
|
||||||
|
sublist = subclause->args;
|
||||||
else
|
else
|
||||||
sublist = lcons(lfirst(orclause), NIL);
|
sublist = lcons(subclause, NIL);
|
||||||
|
/* expansion call... */
|
||||||
pathnode->indexqual = lappend(pathnode->indexqual,
|
pathnode->indexqual = lappend(pathnode->indexqual,
|
||||||
sublist);
|
sublist);
|
||||||
}
|
}
|
||||||
@ -224,18 +227,8 @@ best_or_subclause_index(Query *root,
|
|||||||
Cost *retCost, /* return value */
|
Cost *retCost, /* return value */
|
||||||
Cost *retSelec) /* return value */
|
Cost *retSelec) /* return value */
|
||||||
{
|
{
|
||||||
Oid relid = getrelid(lfirsti(rel->relids),
|
|
||||||
root->rtable);
|
|
||||||
Oid opno = ((Oper *) subclause->oper)->opno;
|
|
||||||
AttrNumber attno = (get_leftop(subclause))->varattno;
|
|
||||||
bool constant_on_right = non_null((Expr *) get_rightop(subclause));
|
|
||||||
Datum value;
|
|
||||||
int flag;
|
|
||||||
List *opnos,
|
|
||||||
*attnos,
|
|
||||||
*values,
|
|
||||||
*flags;
|
|
||||||
bool first_run = true;
|
bool first_run = true;
|
||||||
|
List *indexquals;
|
||||||
List *ilist;
|
List *ilist;
|
||||||
|
|
||||||
/* if we don't match anything, return zeros */
|
/* if we don't match anything, return zeros */
|
||||||
@ -243,37 +236,25 @@ best_or_subclause_index(Query *root,
|
|||||||
*retCost = (Cost) 0.0;
|
*retCost = (Cost) 0.0;
|
||||||
*retSelec = (Cost) 0.0;
|
*retSelec = (Cost) 0.0;
|
||||||
|
|
||||||
if (constant_on_right) /* XXX looks pretty bogus ... tgl */
|
/* convert 'or' subclause to an indexqual list */
|
||||||
value = ((Const *) get_rightop(subclause))->constvalue;
|
if (and_clause((Node *) subclause))
|
||||||
|
indexquals = subclause->args;
|
||||||
else
|
else
|
||||||
value = NameGetDatum("");
|
indexquals = lcons(subclause, NIL);
|
||||||
if (constant_on_right)
|
/* expansion call... */
|
||||||
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
|
|
||||||
else
|
|
||||||
flag = _SELEC_CONSTANT_RIGHT_;
|
|
||||||
|
|
||||||
/* prebuild lists since we will pass same list to each index */
|
|
||||||
opnos = lconsi(opno, NIL);
|
|
||||||
attnos = lconsi(attno, NIL);
|
|
||||||
values = lconsi(value, NIL);
|
|
||||||
flags = lconsi(flag, NIL);
|
|
||||||
|
|
||||||
foreach(ilist, indices)
|
foreach(ilist, indices)
|
||||||
{
|
{
|
||||||
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
|
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
|
||||||
Oid indexid = (Oid) lfirsti(index->relids);
|
Oid indexid = (Oid) lfirsti(index->relids);
|
||||||
Cost subcost;
|
Cost subcost;
|
||||||
float npages,
|
float npages;
|
||||||
selec;
|
float selec;
|
||||||
|
|
||||||
index_selectivity(indexid,
|
index_selectivity(root,
|
||||||
index->classlist,
|
lfirsti(rel->relids),
|
||||||
opnos,
|
indexid,
|
||||||
relid,
|
indexquals,
|
||||||
attnos,
|
|
||||||
values,
|
|
||||||
flags,
|
|
||||||
1,
|
|
||||||
&npages,
|
&npages,
|
||||||
&selec);
|
&selec);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.41 1999/07/24 23:21:13 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.42 1999/07/25 23:07:25 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
static bool fix_opid_walker(Node *node, void *context);
|
static bool fix_opid_walker(Node *node, void *context);
|
||||||
|
static int is_single_func(Node *node);
|
||||||
|
|
||||||
|
|
||||||
Expr *
|
Expr *
|
||||||
@ -533,36 +534,36 @@ fix_opids(List *clauses)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* get_relattval
|
* get_relattval
|
||||||
* For a non-join clause, returns a list consisting of the
|
* Extract information from a restriction or join clause for
|
||||||
* relid,
|
* selectivity estimation. The inputs are an expression
|
||||||
* attno,
|
* and a relation number (which can be 0 if we don't care which
|
||||||
* value of the CONST node (if any), and a
|
* relation is used; that'd normally be the case for restriction
|
||||||
* flag indicating whether the value appears on the left or right
|
* clauses, where the caller already knows that only one relation
|
||||||
* of the operator and whether the value varied.
|
* is referenced in the clause). The routine checks that the
|
||||||
*
|
* expression is of the form (var op something) or (something op var)
|
||||||
* OLD OBSOLETE COMMENT FOLLOWS:
|
* where the var is an attribute of the specified relation, or
|
||||||
* If 'clause' is not of the format (op var node) or (op node var),
|
* a function of a var of the specified relation. If so, it
|
||||||
* or if the var refers to a nested attribute, then -1's are returned for
|
* returns the following info:
|
||||||
* everything but the value a blank string "" (pointer to \0) is
|
* the found relation number (same as targetrelid unless that is 0)
|
||||||
* returned for the value if it is unknown or null.
|
* the found var number (or InvalidAttrNumber if a function)
|
||||||
* END OF OLD OBSOLETE COMMENT.
|
* if the "something" is a constant, the value of the constant
|
||||||
* NEW COMMENT:
|
* flags indicating whether a constant was found, and on which side.
|
||||||
* when defining rules one of the attributes of the operator can
|
* Default values are returned if the expression is too complicated,
|
||||||
* be a Param node (which is supposed to be treated as a constant).
|
* specifically -1 for the relid and attno, 0 for the constant value.
|
||||||
* However as there is no value specified for a parameter until run time
|
* Note that InvalidAttrNumber is *not* -1, but 0.
|
||||||
* this routine used to return "" as value, which caused 'compute_selec'
|
|
||||||
* to bomb (because it was expecting a lisp integer and got back a lisp
|
|
||||||
* string). Now the code returns a plain old good "lispInteger(0)".
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
get_relattval(Node *clause,
|
get_relattval(Node *clause,
|
||||||
|
int targetrelid,
|
||||||
int *relid,
|
int *relid,
|
||||||
AttrNumber *attno,
|
AttrNumber *attno,
|
||||||
Datum *constval,
|
Datum *constval,
|
||||||
int *flag)
|
int *flag)
|
||||||
{
|
{
|
||||||
Var *left,
|
Var *left,
|
||||||
*right;
|
*right,
|
||||||
|
*other;
|
||||||
|
int funcvarno;
|
||||||
|
|
||||||
/* Careful; the passed clause might not be a binary operator at all */
|
/* Careful; the passed clause might not be a binary operator at all */
|
||||||
|
|
||||||
@ -575,71 +576,96 @@ get_relattval(Node *clause,
|
|||||||
if (!right)
|
if (!right)
|
||||||
goto default_results;
|
goto default_results;
|
||||||
|
|
||||||
if (IsA(left, Var) &&IsA(right, Const))
|
/* First look for the var or func */
|
||||||
|
|
||||||
|
if (IsA(left, Var) &&
|
||||||
|
(targetrelid == 0 || targetrelid == left->varno))
|
||||||
{
|
{
|
||||||
*relid = left->varno;
|
*relid = left->varno;
|
||||||
*attno = left->varattno;
|
*attno = left->varattno;
|
||||||
*constval = ((Const *) right)->constvalue;
|
*flag = SEL_RIGHT;
|
||||||
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
|
|
||||||
}
|
}
|
||||||
else if (IsA(left, Var) &&IsA(right, Param))
|
else if (IsA(right, Var) &&
|
||||||
{
|
(targetrelid == 0 || targetrelid == right->varno))
|
||||||
*relid = left->varno;
|
|
||||||
*attno = left->varattno;
|
|
||||||
*constval = 0;
|
|
||||||
*flag = (_SELEC_NOT_CONSTANT_);
|
|
||||||
}
|
|
||||||
else if (is_funcclause((Node *) left) && IsA(right, Const))
|
|
||||||
{
|
|
||||||
List *vars = pull_var_clause((Node *) left);
|
|
||||||
|
|
||||||
*relid = ((Var *) lfirst(vars))->varno;
|
|
||||||
*attno = InvalidAttrNumber;
|
|
||||||
*constval = ((Const *) right)->constvalue;
|
|
||||||
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
|
|
||||||
}
|
|
||||||
else if (IsA(right, Var) &&IsA(left, Const))
|
|
||||||
{
|
{
|
||||||
*relid = right->varno;
|
*relid = right->varno;
|
||||||
*attno = right->varattno;
|
*attno = right->varattno;
|
||||||
*constval = ((Const *) left)->constvalue;
|
*flag = 0;
|
||||||
*flag = (_SELEC_IS_CONSTANT_);
|
|
||||||
}
|
}
|
||||||
else if (IsA(right, Var) &&IsA(left, Param))
|
else if ((funcvarno = is_single_func((Node *) left)) != 0 &&
|
||||||
|
(targetrelid == 0 || targetrelid == funcvarno))
|
||||||
{
|
{
|
||||||
*relid = right->varno;
|
*relid = funcvarno;
|
||||||
*attno = right->varattno;
|
|
||||||
*constval = 0;
|
|
||||||
*flag = (_SELEC_NOT_CONSTANT_);
|
|
||||||
}
|
|
||||||
else if (is_funcclause((Node *) right) && IsA(left, Const))
|
|
||||||
{
|
|
||||||
List *vars = pull_var_clause((Node *) right);
|
|
||||||
|
|
||||||
*relid = ((Var *) lfirst(vars))->varno;
|
|
||||||
*attno = InvalidAttrNumber;
|
*attno = InvalidAttrNumber;
|
||||||
*constval = ((Const *) left)->constvalue;
|
*flag = SEL_RIGHT;
|
||||||
*flag = (_SELEC_IS_CONSTANT_);
|
}
|
||||||
|
else if ((funcvarno = is_single_func((Node *) right)) != 0 &&
|
||||||
|
(targetrelid == 0 || targetrelid == funcvarno))
|
||||||
|
{
|
||||||
|
*relid = funcvarno;
|
||||||
|
*attno = InvalidAttrNumber;
|
||||||
|
*flag = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Duh, it's too complicated for me... */
|
/* Duh, it's too complicated for me... */
|
||||||
default_results:
|
default_results:
|
||||||
*relid = _SELEC_VALUE_UNKNOWN_;
|
*relid = -1;
|
||||||
*attno = _SELEC_VALUE_UNKNOWN_;
|
*attno = -1;
|
||||||
|
*constval = 0;
|
||||||
|
*flag = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK, we identified the var or func; now look at the other side */
|
||||||
|
|
||||||
|
other = (*flag == 0) ? left : right;
|
||||||
|
|
||||||
|
if (IsA(other, Const))
|
||||||
|
{
|
||||||
|
*constval = ((Const *) other)->constvalue;
|
||||||
|
*flag |= SEL_CONSTANT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*constval = 0;
|
*constval = 0;
|
||||||
*flag = (_SELEC_NOT_CONSTANT_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_relsatts
|
* is_single_func
|
||||||
|
* If the given expression is a function of a single relation,
|
||||||
|
* return the relation number; else return 0
|
||||||
|
*/
|
||||||
|
static int is_single_func(Node *node)
|
||||||
|
{
|
||||||
|
if (is_funcclause(node))
|
||||||
|
{
|
||||||
|
List *vars = pull_var_clause(node);
|
||||||
|
|
||||||
|
if (vars != NIL)
|
||||||
|
{
|
||||||
|
int funcvarno = ((Var *) lfirst(vars))->varno;
|
||||||
|
/* need to check that all args of func are same relation */
|
||||||
|
while ((vars = lnext(vars)) != NIL)
|
||||||
|
{
|
||||||
|
if (((Var *) lfirst(vars))->varno != funcvarno)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return funcvarno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_rels_atts
|
||||||
*
|
*
|
||||||
* Returns a list
|
* Returns the info
|
||||||
* ( relid1 attno1 relid2 attno2 )
|
* ( relid1 attno1 relid2 attno2 )
|
||||||
* for a joinclause.
|
* for a joinclause.
|
||||||
*
|
*
|
||||||
* If the clause is not of the form (op var var) or if any of the vars
|
* If the clause is not of the form (var op var) or if any of the vars
|
||||||
* refer to nested attributes, then -1's are returned.
|
* refer to nested attributes, then -1's are returned.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -650,6 +676,12 @@ get_rels_atts(Node *clause,
|
|||||||
int *relid2,
|
int *relid2,
|
||||||
AttrNumber *attno2)
|
AttrNumber *attno2)
|
||||||
{
|
{
|
||||||
|
/* set default values */
|
||||||
|
*relid1 = -1;
|
||||||
|
*attno1 = -1;
|
||||||
|
*relid2 = -1;
|
||||||
|
*attno2 = -1;
|
||||||
|
|
||||||
if (is_opclause(clause))
|
if (is_opclause(clause))
|
||||||
{
|
{
|
||||||
Var *left = get_leftop((Expr *) clause);
|
Var *left = get_leftop((Expr *) clause);
|
||||||
@ -657,47 +689,31 @@ get_rels_atts(Node *clause,
|
|||||||
|
|
||||||
if (left && right)
|
if (left && right)
|
||||||
{
|
{
|
||||||
bool var_left = IsA(left, Var);
|
int funcvarno;
|
||||||
bool var_right = IsA(right, Var);
|
|
||||||
bool varexpr_left = (bool) ((IsA(left, Func) ||IsA(left, Oper)) &&
|
|
||||||
contain_var_clause((Node *) left));
|
|
||||||
bool varexpr_right = (bool) ((IsA(right, Func) ||IsA(right, Oper)) &&
|
|
||||||
contain_var_clause((Node *) right));
|
|
||||||
|
|
||||||
if (var_left && var_right)
|
if (IsA(left, Var))
|
||||||
{
|
{
|
||||||
|
|
||||||
*relid1 = left->varno;
|
*relid1 = left->varno;
|
||||||
*attno1 = left->varoattno;
|
*attno1 = left->varattno;
|
||||||
*relid2 = right->varno;
|
|
||||||
*attno2 = right->varoattno;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (var_left && varexpr_right)
|
else if ((funcvarno = is_single_func((Node *) left)) != 0)
|
||||||
{
|
{
|
||||||
|
*relid1 = funcvarno;
|
||||||
*relid1 = left->varno;
|
*attno1 = InvalidAttrNumber;
|
||||||
*attno1 = left->varoattno;
|
|
||||||
*relid2 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*attno2 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (varexpr_left && var_right)
|
|
||||||
|
if (IsA(right, Var))
|
||||||
{
|
{
|
||||||
|
|
||||||
*relid1 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*attno1 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*relid2 = right->varno;
|
*relid2 = right->varno;
|
||||||
*attno2 = right->varoattno;
|
*attno2 = right->varattno;
|
||||||
return;
|
}
|
||||||
|
else if ((funcvarno = is_single_func((Node *) right)) != 0)
|
||||||
|
{
|
||||||
|
*relid2 = funcvarno;
|
||||||
|
*attno2 = InvalidAttrNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*relid1 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*attno1 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*relid2 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
*attno2 = _SELEC_VALUE_UNKNOWN_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------
|
/*--------------------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.47 1999/07/24 23:21:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.48 1999/07/25 23:07:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -334,7 +334,12 @@ create_index_path(Query *root,
|
|||||||
pathnode->path.pathorder = makeNode(PathOrder);
|
pathnode->path.pathorder = makeNode(PathOrder);
|
||||||
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
|
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
|
||||||
pathnode->path.pathorder->ord.sortop = index->ordering;
|
pathnode->path.pathorder->ord.sortop = index->ordering;
|
||||||
|
pathnode->path.pathkeys = NIL;
|
||||||
|
|
||||||
|
/* Note that we are making a pathnode for a single-scan indexscan;
|
||||||
|
* therefore, both indexid and indexqual should be single-element
|
||||||
|
* lists (unless indexqual is empty).
|
||||||
|
*/
|
||||||
pathnode->indexid = index->relids;
|
pathnode->indexid = index->relids;
|
||||||
pathnode->indexkeys = index->indexkeys;
|
pathnode->indexkeys = index->indexkeys;
|
||||||
pathnode->indexqual = NIL;
|
pathnode->indexqual = NIL;
|
||||||
@ -344,7 +349,7 @@ create_index_path(Query *root,
|
|||||||
* JMH, 7/7/92
|
* JMH, 7/7/92
|
||||||
*/
|
*/
|
||||||
pathnode->path.loc_restrictinfo = set_difference((List *) copyObject((Node *) rel->restrictinfo),
|
pathnode->path.loc_restrictinfo = set_difference((List *) copyObject((Node *) rel->restrictinfo),
|
||||||
(List *) restriction_clauses);
|
restriction_clauses);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The index must have an ordering for the path to have (ordering)
|
* The index must have an ordering for the path to have (ordering)
|
||||||
@ -385,49 +390,28 @@ create_index_path(Query *root,
|
|||||||
index->pages,
|
index->pages,
|
||||||
index->tuples,
|
index->tuples,
|
||||||
false);
|
false);
|
||||||
#ifdef NOT_USED
|
|
||||||
/* add in expensive functions cost! -- JMH, 7/7/92 */
|
|
||||||
if (XfuncMode != XFUNC_OFF)
|
|
||||||
{
|
|
||||||
pathnode->path_cost = (pathnode->path_cost +
|
|
||||||
xfunc_get_path_cost((Path *) pathnode));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute scan cost for the case when 'index' is used with a
|
* Compute scan cost for the case when 'index' is used with a
|
||||||
* restriction clause.
|
* restriction clause.
|
||||||
*/
|
*/
|
||||||
List *attnos;
|
List *indexquals;
|
||||||
List *values;
|
|
||||||
List *flags;
|
|
||||||
float npages;
|
float npages;
|
||||||
float selec;
|
float selec;
|
||||||
Cost clausesel;
|
Cost clausesel;
|
||||||
|
|
||||||
get_relattvals(restriction_clauses,
|
indexquals = get_actual_clauses(restriction_clauses);
|
||||||
&attnos,
|
|
||||||
&values,
|
index_selectivity(root,
|
||||||
&flags);
|
lfirsti(rel->relids),
|
||||||
index_selectivity(lfirsti(index->relids),
|
lfirsti(index->relids),
|
||||||
index->classlist,
|
indexquals,
|
||||||
get_opnos(restriction_clauses),
|
|
||||||
getrelid(lfirsti(rel->relids),
|
|
||||||
root->rtable),
|
|
||||||
attnos,
|
|
||||||
values,
|
|
||||||
flags,
|
|
||||||
length(restriction_clauses),
|
|
||||||
&npages,
|
&npages,
|
||||||
&selec);
|
&selec);
|
||||||
/* each clause gets an equal selectivity */
|
|
||||||
clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
|
|
||||||
|
|
||||||
pathnode->indexqual = lcons(get_actual_clauses(restriction_clauses),
|
pathnode->indexqual = lcons(indexquals, NIL);
|
||||||
NIL);
|
|
||||||
pathnode->path.path_cost = cost_index(lfirsti(index->relids),
|
pathnode->path.path_cost = cost_index(lfirsti(index->relids),
|
||||||
(int) npages,
|
(int) npages,
|
||||||
selec,
|
selec,
|
||||||
@ -437,21 +421,24 @@ create_index_path(Query *root,
|
|||||||
index->tuples,
|
index->tuples,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set selectivities of clauses used with index to the selectivity
|
||||||
|
* of this index, subdividing the selectivity equally over each of
|
||||||
|
* the clauses.
|
||||||
|
* XXX Can this divide the selectivities in a better way?
|
||||||
|
* XXX In fact, why the heck are we doing this at all? We already
|
||||||
|
* set the cost for the indexpath.
|
||||||
|
*/
|
||||||
|
clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
|
||||||
|
set_clause_selectivities(restriction_clauses, clausesel);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
/* add in expensive functions cost! -- JMH, 7/7/92 */
|
/* add in expensive functions cost! -- JMH, 7/7/92 */
|
||||||
if (XfuncMode != XFUNC_OFF)
|
if (XfuncMode != XFUNC_OFF)
|
||||||
pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
|
pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Set selectivities of clauses used with index to the selectivity
|
|
||||||
* of this index, subdividing the selectivity equally over each of
|
|
||||||
* the clauses.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* XXX Can this divide the selectivities in a better way? */
|
|
||||||
set_clause_selectivities(restriction_clauses, clausesel);
|
|
||||||
}
|
|
||||||
return pathnode;
|
return pathnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.35 1999/07/17 20:17:18 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.36 1999/07/25 23:07:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,16 +20,20 @@
|
|||||||
#include "catalog/catname.h"
|
#include "catalog/catname.h"
|
||||||
#include "catalog/pg_amop.h"
|
#include "catalog/pg_amop.h"
|
||||||
#include "catalog/pg_inherits.h"
|
#include "catalog/pg_inherits.h"
|
||||||
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/internal.h"
|
#include "optimizer/internal.h"
|
||||||
#include "optimizer/plancat.h"
|
#include "optimizer/plancat.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys,
|
static void IndexSelectivity(Oid indexrelid, Oid baserelid, int nIndexKeys,
|
||||||
Oid *AccessMethodOperatorClasses, Oid *operatorObjectIds,
|
Oid *operatorObjectIds,
|
||||||
int32 *varAttributeNumbers, char **constValues, int32 *constFlags,
|
AttrNumber *varAttributeNumbers,
|
||||||
float *idxPages, float *idxSelec);
|
Datum *constValues,
|
||||||
|
int *constFlags,
|
||||||
|
float *idxPages,
|
||||||
|
float *idxSelec);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -212,85 +216,75 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* index_selectivity
|
* index_selectivity
|
||||||
|
* Estimate the selectivity of an index scan with the given index quals.
|
||||||
*
|
*
|
||||||
* Call util/plancat.c:IndexSelectivity with the indicated arguments.
|
* NOTE: an indexscan plan node can actually represent several passes,
|
||||||
*
|
* but here we consider the cost of just one pass.
|
||||||
* 'indid' is the index OID
|
|
||||||
* 'classes' is a list of index key classes
|
|
||||||
* 'opnos' is a list of index key operator OIDs
|
|
||||||
* 'relid' is the OID of the relation indexed
|
|
||||||
* 'attnos' is a list of the relation attnos which the index keys over
|
|
||||||
* 'values' is a list of the values of the clause's constants
|
|
||||||
* 'flags' is a list of fixnums which describe the constants
|
|
||||||
* 'nkeys' is the number of index keys
|
|
||||||
*
|
|
||||||
* Returns two floats: index pages and index selectivity in 'idxPages' and
|
|
||||||
* 'idxSelec'.
|
|
||||||
*
|
*
|
||||||
|
* 'root' is the query root
|
||||||
|
* 'relid' is the RT index of the relation being scanned
|
||||||
|
* 'indexid' is the OID of the index to be used
|
||||||
|
* 'indexquals' is the list of qual condition exprs (implicit AND semantics)
|
||||||
|
* '*idxPages' receives an estimate of the number of index pages touched
|
||||||
|
* '*idxSelec' receives an estimate of selectivity of the scan
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
index_selectivity(Oid indid,
|
index_selectivity(Query *root,
|
||||||
Oid *classes,
|
int relid,
|
||||||
List *opnos,
|
Oid indexid,
|
||||||
Oid relid,
|
List *indexquals,
|
||||||
List *attnos,
|
|
||||||
List *values,
|
|
||||||
List *flags,
|
|
||||||
int32 nkeys,
|
|
||||||
float *idxPages,
|
float *idxPages,
|
||||||
float *idxSelec)
|
float *idxSelec)
|
||||||
{
|
{
|
||||||
|
int nclauses = length(indexquals);
|
||||||
Oid *opno_array;
|
Oid *opno_array;
|
||||||
int *attno_array,
|
AttrNumber *attno_array;
|
||||||
*flag_array;
|
Datum *value_array;
|
||||||
char **value_array;
|
int *flag_array;
|
||||||
int i = 0;
|
List *q;
|
||||||
List *xopno,
|
int i;
|
||||||
*xattno,
|
|
||||||
*value,
|
|
||||||
*flag;
|
|
||||||
|
|
||||||
if (length(opnos) != nkeys || length(attnos) != nkeys ||
|
if (nclauses <= 0)
|
||||||
length(values) != nkeys || length(flags) != nkeys)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
*idxPages = 0.0;
|
*idxPages = 0.0;
|
||||||
*idxSelec = 1.0;
|
*idxSelec = 1.0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
opno_array = (Oid *) palloc(nclauses * sizeof(Oid));
|
||||||
opno_array = (Oid *) palloc(nkeys * sizeof(Oid));
|
attno_array = (AttrNumber *) palloc(nclauses * sizeof(AttrNumber));
|
||||||
attno_array = (int *) palloc(nkeys * sizeof(int32));
|
value_array = (Datum *) palloc(nclauses * sizeof(Datum));
|
||||||
value_array = (char **) palloc(nkeys * sizeof(char *));
|
flag_array = (int *) palloc(nclauses * sizeof(int));
|
||||||
flag_array = (int *) palloc(nkeys * sizeof(int32));
|
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(xopno, opnos)
|
foreach(q, indexquals)
|
||||||
opno_array[i++] = lfirsti(xopno);
|
{
|
||||||
|
Node *expr = (Node *) lfirst(q);
|
||||||
|
int dummyrelid;
|
||||||
|
|
||||||
i = 0;
|
if (is_opclause(expr))
|
||||||
foreach(xattno, attnos)
|
opno_array[i] = ((Oper *) ((Expr *) expr)->oper)->opno;
|
||||||
attno_array[i++] = lfirsti(xattno);
|
else
|
||||||
|
opno_array[i] = InvalidOid;
|
||||||
|
|
||||||
i = 0;
|
get_relattval(expr, relid, &dummyrelid, &attno_array[i],
|
||||||
foreach(value, values)
|
&value_array[i], &flag_array[i]);
|
||||||
value_array[i++] = (char *) lfirst(value);
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
i = 0;
|
IndexSelectivity(indexid,
|
||||||
foreach(flag, flags)
|
getrelid(relid, root->rtable),
|
||||||
flag_array[i++] = lfirsti(flag);
|
nclauses,
|
||||||
|
|
||||||
IndexSelectivity(indid,
|
|
||||||
relid,
|
|
||||||
nkeys,
|
|
||||||
classes, /* not used */
|
|
||||||
opno_array,
|
opno_array,
|
||||||
attno_array,
|
attno_array,
|
||||||
value_array,
|
value_array,
|
||||||
flag_array,
|
flag_array,
|
||||||
idxPages,
|
idxPages,
|
||||||
idxSelec);
|
idxSelec);
|
||||||
return;
|
|
||||||
|
pfree(opno_array);
|
||||||
|
pfree(attno_array);
|
||||||
|
pfree(value_array);
|
||||||
|
pfree(flag_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -312,8 +306,8 @@ restriction_selectivity(Oid functionObjectId,
|
|||||||
Oid operatorObjectId,
|
Oid operatorObjectId,
|
||||||
Oid relationObjectId,
|
Oid relationObjectId,
|
||||||
AttrNumber attributeNumber,
|
AttrNumber attributeNumber,
|
||||||
char *constValue,
|
Datum constValue,
|
||||||
int32 constFlag)
|
int constFlag)
|
||||||
{
|
{
|
||||||
float64 result;
|
float64 result;
|
||||||
|
|
||||||
@ -456,35 +450,29 @@ VersionGetParents(Oid verrelid)
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IdexSelectivity
|
* IndexSelectivity
|
||||||
*
|
*
|
||||||
* Retrieves the 'amopnpages' and 'amopselect' parameters for each
|
* Calls the 'amopnpages' and 'amopselect' functions for each
|
||||||
* AM operator when a given index (specified by 'indexrelid') is used.
|
* AM operator when a given index (specified by 'indexrelid') is used.
|
||||||
* These two parameters are returned by copying them to into an array of
|
* The total number of pages and product of the selectivities are returned.
|
||||||
* floats.
|
|
||||||
*
|
*
|
||||||
* Assumption: the attribute numbers and operator ObjectIds are in order
|
* Assumption: the attribute numbers and operator ObjectIds are in order
|
||||||
* WRT to each other (otherwise, you have no way of knowing which
|
* WRT to each other (otherwise, you have no way of knowing which
|
||||||
* AM operator class or attribute number corresponds to which operator.
|
* AM operator class or attribute number corresponds to which operator.
|
||||||
*
|
*
|
||||||
|
* 'nIndexKeys' is the number of qual clauses in use
|
||||||
* 'varAttributeNumbers' contains attribute numbers for variables
|
* 'varAttributeNumbers' contains attribute numbers for variables
|
||||||
* 'constValues' contains the constant values
|
* 'constValues' contains the constant values
|
||||||
* 'constFlags' describes how to treat the constants in each clause
|
* 'constFlags' describes how to treat the constants in each clause
|
||||||
* 'nIndexKeys' describes how many keys the index actually has
|
|
||||||
*
|
|
||||||
* Returns 'selectivityInfo' filled with the sum of all pages touched
|
|
||||||
* and the product of each clause's selectivity.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
IndexSelectivity(Oid indexrelid,
|
IndexSelectivity(Oid indexrelid,
|
||||||
Oid indrelid,
|
Oid baserelid,
|
||||||
int32 nIndexKeys,
|
int nIndexKeys,
|
||||||
Oid *AccessMethodOperatorClasses, /* XXX not used? */
|
|
||||||
Oid *operatorObjectIds,
|
Oid *operatorObjectIds,
|
||||||
int32 *varAttributeNumbers,
|
AttrNumber *varAttributeNumbers,
|
||||||
char **constValues,
|
Datum *constValues,
|
||||||
int32 *constFlags,
|
int *constFlags,
|
||||||
float *idxPages,
|
float *idxPages,
|
||||||
float *idxSelec)
|
float *idxSelec)
|
||||||
{
|
{
|
||||||
@ -493,6 +481,7 @@ IndexSelectivity(Oid indexrelid,
|
|||||||
HeapTuple indexTuple,
|
HeapTuple indexTuple,
|
||||||
amopTuple,
|
amopTuple,
|
||||||
indRel;
|
indRel;
|
||||||
|
Form_pg_class indexrelation;
|
||||||
Form_pg_index index;
|
Form_pg_index index;
|
||||||
Form_pg_amop amop;
|
Form_pg_amop amop;
|
||||||
Oid indclass;
|
Oid indclass;
|
||||||
@ -510,7 +499,8 @@ IndexSelectivity(Oid indexrelid,
|
|||||||
if (!HeapTupleIsValid(indRel))
|
if (!HeapTupleIsValid(indRel))
|
||||||
elog(ERROR, "IndexSelectivity: index %u not found",
|
elog(ERROR, "IndexSelectivity: index %u not found",
|
||||||
indexrelid);
|
indexrelid);
|
||||||
relam = ((Form_pg_class) GETSTRUCT(indRel))->relam;
|
indexrelation = (Form_pg_class) GETSTRUCT(indRel);
|
||||||
|
relam = indexrelation->relam;
|
||||||
|
|
||||||
indexTuple = SearchSysCacheTuple(INDEXRELID,
|
indexTuple = SearchSysCacheTuple(INDEXRELID,
|
||||||
ObjectIdGetDatum(indexrelid),
|
ObjectIdGetDatum(indexrelid),
|
||||||
@ -530,9 +520,8 @@ IndexSelectivity(Oid indexrelid,
|
|||||||
|
|
||||||
npages = 0.0;
|
npages = 0.0;
|
||||||
select = 1.0;
|
select = 1.0;
|
||||||
for (n = 0; n < nIndexKeys; ++n)
|
for (n = 0; n < nIndexKeys; n++)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the AM class for this key.
|
* Find the AM class for this key.
|
||||||
*
|
*
|
||||||
@ -571,45 +560,39 @@ IndexSelectivity(Oid indexrelid,
|
|||||||
ObjectIdGetDatum(relam),
|
ObjectIdGetDatum(relam),
|
||||||
0);
|
0);
|
||||||
if (!HeapTupleIsValid(amopTuple))
|
if (!HeapTupleIsValid(amopTuple))
|
||||||
elog(ERROR, "IndexSelectivity: no amop %u %u",
|
elog(ERROR, "IndexSelectivity: no amop %u %u %u",
|
||||||
indclass, operatorObjectIds[n]);
|
indclass, operatorObjectIds[n], relam);
|
||||||
amop = (Form_pg_amop) GETSTRUCT(amopTuple);
|
amop = (Form_pg_amop) GETSTRUCT(amopTuple);
|
||||||
|
|
||||||
if (!nphack)
|
if (!nphack)
|
||||||
{
|
{
|
||||||
amopnpages = (float64) fmgr(amop->amopnpages,
|
amopnpages = (float64) fmgr(amop->amopnpages,
|
||||||
(char *) operatorObjectIds[n],
|
(char *) operatorObjectIds[n],
|
||||||
(char *) indrelid,
|
(char *) baserelid,
|
||||||
(char *) varAttributeNumbers[n],
|
(char *) (int) varAttributeNumbers[n],
|
||||||
(char *) constValues[n],
|
(char *) constValues[n],
|
||||||
(char *) constFlags[n],
|
(char *) constFlags[n],
|
||||||
(char *) nIndexKeys,
|
(char *) nIndexKeys,
|
||||||
(char *) indexrelid);
|
(char *) indexrelid);
|
||||||
#ifdef NOT_USED
|
if (PointerIsValid(amopnpages))
|
||||||
/*
|
npages += *amopnpages;
|
||||||
* So cool guys! Npages for x > 10 and x < 20 is twice as
|
|
||||||
* npages for x > 10! - vadim 04/09/97
|
|
||||||
*/
|
|
||||||
npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
|
|
||||||
if ((i = npages) < npages) /* ceil(npages)? */
|
|
||||||
npages += 1.0;
|
|
||||||
#endif
|
|
||||||
npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
amopselect = (float64) fmgr(amop->amopselect,
|
amopselect = (float64) fmgr(amop->amopselect,
|
||||||
(char *) operatorObjectIds[n],
|
(char *) operatorObjectIds[n],
|
||||||
(char *) indrelid,
|
(char *) baserelid,
|
||||||
(char *) varAttributeNumbers[n],
|
(char *) (int) varAttributeNumbers[n],
|
||||||
(char *) constValues[n],
|
(char *) constValues[n],
|
||||||
(char *) constFlags[n],
|
(char *) constFlags[n],
|
||||||
(char *) nIndexKeys,
|
(char *) nIndexKeys,
|
||||||
(char *) indexrelid);
|
(char *) indexrelid);
|
||||||
|
|
||||||
|
if (PointerIsValid(amopselect))
|
||||||
|
{
|
||||||
|
select *= *amopselect;
|
||||||
if (nphack && varAttributeNumbers[n] == index->indkey[0])
|
if (nphack && varAttributeNumbers[n] == index->indkey[0])
|
||||||
fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
|
fattr_select *= *amopselect;
|
||||||
|
}
|
||||||
select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -618,7 +601,7 @@ IndexSelectivity(Oid indexrelid,
|
|||||||
*/
|
*/
|
||||||
if (nphack)
|
if (nphack)
|
||||||
{
|
{
|
||||||
npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages;
|
npages = fattr_select * indexrelation->relpages;
|
||||||
*idxPages = ceil((double) npages);
|
*idxPages = ceil((double) npages);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.7 1999/07/24 23:21:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.8 1999/07/25 23:07:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -44,144 +44,14 @@ restriction_is_or_clause(RestrictInfo *restrictinfo)
|
|||||||
List *
|
List *
|
||||||
get_actual_clauses(List *restrictinfo_list)
|
get_actual_clauses(List *restrictinfo_list)
|
||||||
{
|
{
|
||||||
List *temp = NIL;
|
|
||||||
List *result = NIL;
|
List *result = NIL;
|
||||||
RestrictInfo *clause = (RestrictInfo *) NULL;
|
|
||||||
|
|
||||||
foreach(temp, restrictinfo_list)
|
|
||||||
{
|
|
||||||
clause = (RestrictInfo *) lfirst(temp);
|
|
||||||
result = lappend(result, clause->clause);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX NOTE:
|
|
||||||
* The following routines must return their contents in the same order
|
|
||||||
* (e.g., the first clause's info should be first, and so on) or else
|
|
||||||
* get_index_sel() won't work.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get_relattvals
|
|
||||||
* For each member of a list of restrictinfo nodes to be used with an
|
|
||||||
* index, create a vectori-long specifying:
|
|
||||||
* the attnos,
|
|
||||||
* the values of the clause constants, and
|
|
||||||
* flags indicating the type and location of the constant within
|
|
||||||
* each clause.
|
|
||||||
* Each clause is of the form (op var some_type_of_constant), thus the
|
|
||||||
* flag indicating whether the constant is on the left or right should
|
|
||||||
* always be *SELEC-CONSTANT-RIGHT*.
|
|
||||||
*
|
|
||||||
* 'restrictinfo_list' is a list of restrictinfo nodes
|
|
||||||
*
|
|
||||||
* Returns a list of vectori-longs.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
get_relattvals(List *restrictinfo_list,
|
|
||||||
List **attnos,
|
|
||||||
List **values,
|
|
||||||
List **flags)
|
|
||||||
{
|
|
||||||
List *result1 = NIL;
|
|
||||||
List *result2 = NIL;
|
|
||||||
List *result3 = NIL;
|
|
||||||
RestrictInfo *temp = (RestrictInfo *) NULL;
|
|
||||||
List *i = NIL;
|
|
||||||
|
|
||||||
foreach(i, restrictinfo_list)
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
AttrNumber attno;
|
|
||||||
Datum constval;
|
|
||||||
int flag;
|
|
||||||
|
|
||||||
temp = (RestrictInfo *) lfirst(i);
|
|
||||||
get_relattval((Node *) temp->clause, &dummy, &attno, &constval, &flag);
|
|
||||||
result1 = lappendi(result1, (int) attno);
|
|
||||||
result2 = lappendi(result2, constval);
|
|
||||||
result3 = lappendi(result3, flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
*attnos = result1;
|
|
||||||
*values = result2;
|
|
||||||
*flags = result3;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get_joinvars
|
|
||||||
* Given a list of join restrictinfo nodes to be used with the index
|
|
||||||
* of an inner join relation, return three lists consisting of:
|
|
||||||
* the attributes corresponding to the inner join relation
|
|
||||||
* the value of the inner var clause (always "")
|
|
||||||
* whether the attribute appears on the left or right side of
|
|
||||||
* the operator.
|
|
||||||
*
|
|
||||||
* 'relid' is the inner join relation
|
|
||||||
* 'restrictinfo_list' is a list of qualification clauses to be used with
|
|
||||||
* 'rel'
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
get_joinvars(Oid relid,
|
|
||||||
List *restrictinfo_list,
|
|
||||||
List **attnos,
|
|
||||||
List **values,
|
|
||||||
List **flags)
|
|
||||||
{
|
|
||||||
List *result1 = NIL;
|
|
||||||
List *result2 = NIL;
|
|
||||||
List *result3 = NIL;
|
|
||||||
List *temp;
|
List *temp;
|
||||||
|
|
||||||
foreach(temp, restrictinfo_list)
|
foreach(temp, restrictinfo_list)
|
||||||
{
|
{
|
||||||
RestrictInfo *restrictinfo = lfirst(temp);
|
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
|
||||||
Expr *clause = restrictinfo->clause;
|
|
||||||
|
|
||||||
if (IsA(get_leftop(clause), Var) &&
|
result = lappend(result, clause->clause);
|
||||||
(relid == (get_leftop(clause))->varno))
|
|
||||||
{
|
|
||||||
result1 = lappendi(result1, (int4) (get_leftop(clause))->varattno);
|
|
||||||
result2 = lappend(result2, "");
|
|
||||||
result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result1 = lappendi(result1, (int4) (get_rightop(clause))->varattno);
|
|
||||||
result2 = lappend(result2, "");
|
|
||||||
result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*attnos = result1;
|
|
||||||
*values = result2;
|
|
||||||
*flags = result3;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get_opnos
|
|
||||||
* Create and return a list containing the clause operators of each member
|
|
||||||
* of a list of restrictinfo nodes to be used with an index.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
List *
|
|
||||||
get_opnos(List *restrictinfo_list)
|
|
||||||
{
|
|
||||||
RestrictInfo *temp = (RestrictInfo *) NULL;
|
|
||||||
List *result = NIL;
|
|
||||||
List *i = NIL;
|
|
||||||
|
|
||||||
foreach(i, restrictinfo_list)
|
|
||||||
{
|
|
||||||
temp = (RestrictInfo *) lfirst(i);
|
|
||||||
result = lappendi(result,
|
|
||||||
(((Oper *) temp->clause->oper)->opno));
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: clauses.h,v 1.22 1999/07/24 23:21:05 tgl Exp $
|
* $Id: clauses.h,v 1.23 1999/07/25 23:07:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -45,8 +45,9 @@ extern bool is_joinable(Node *clause);
|
|||||||
extern bool qual_clause_p(Node *clause);
|
extern bool qual_clause_p(Node *clause);
|
||||||
extern void fix_opid(Node *clause);
|
extern void fix_opid(Node *clause);
|
||||||
extern List *fix_opids(List *clauses);
|
extern List *fix_opids(List *clauses);
|
||||||
extern void get_relattval(Node *clause, int *relid,
|
extern void get_relattval(Node *clause, int targetrelid,
|
||||||
AttrNumber *attno, Datum *constval, int *flag);
|
int *relid, AttrNumber *attno,
|
||||||
|
Datum *constval, int *flag);
|
||||||
extern void get_rels_atts(Node *clause, int *relid1,
|
extern void get_rels_atts(Node *clause, int *relid1,
|
||||||
AttrNumber *attno1, int *relid2, AttrNumber *attno2);
|
AttrNumber *attno1, int *relid2, AttrNumber *attno2);
|
||||||
extern void CommuteClause(Node *clause);
|
extern void CommuteClause(Node *clause);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: internal.h,v 1.22 1999/07/15 15:21:21 momjian Exp $
|
* $Id: internal.h,v 1.23 1999/07/25 23:07:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -63,20 +63,6 @@
|
|||||||
/* used to be -1 */
|
/* used to be -1 */
|
||||||
#define _NONAME_RELATION_ID_ InvalidOid
|
#define _NONAME_RELATION_ID_ InvalidOid
|
||||||
|
|
||||||
/* Identifier for invalid relation OIDs and attribute numbers for use by
|
|
||||||
* selectivity functions
|
|
||||||
*/
|
|
||||||
#define _SELEC_VALUE_UNKNOWN_ (-1)
|
|
||||||
|
|
||||||
/* Flag indicating that a clause constant is really a parameter (or other
|
|
||||||
* non-constant?), a non-parameter, or a constant on the right side
|
|
||||||
* of the clause.
|
|
||||||
*/
|
|
||||||
#define _SELEC_NOT_CONSTANT_ 0
|
|
||||||
#define _SELEC_IS_CONSTANT_ 1
|
|
||||||
#define _SELEC_CONSTANT_LEFT_ 0
|
|
||||||
#define _SELEC_CONSTANT_RIGHT_ 2
|
|
||||||
|
|
||||||
/* #define deactivate_joininfo(joininfo) joininfo->inactive=true*/
|
/* #define deactivate_joininfo(joininfo) joininfo->inactive=true*/
|
||||||
/*#define joininfo_inactive(joininfo) joininfo->inactive */
|
/*#define joininfo_inactive(joininfo) joininfo->inactive */
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: plancat.h,v 1.12 1999/07/15 23:03:58 momjian Exp $
|
* $Id: plancat.h,v 1.13 1999/07/25 23:07:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -46,12 +46,12 @@ extern Cost restriction_selectivity(Oid functionObjectId,
|
|||||||
Oid operatorObjectId,
|
Oid operatorObjectId,
|
||||||
Oid relationObjectId,
|
Oid relationObjectId,
|
||||||
AttrNumber attributeNumber,
|
AttrNumber attributeNumber,
|
||||||
char *constValue,
|
Datum constValue,
|
||||||
int32 constFlag);
|
int constFlag);
|
||||||
|
|
||||||
extern void index_selectivity(Oid indid, Oid *classes, List *opnos,
|
extern void index_selectivity(Query *root, int relid, Oid indexid,
|
||||||
Oid relid, List *attnos, List *values, List *flags,
|
List *indexquals,
|
||||||
int32 nkeys, float *idxPages, float *idxSelec);
|
float *idxPages, float *idxSelec);
|
||||||
|
|
||||||
extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId,
|
extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId,
|
||||||
Oid relationObjectId1, AttrNumber attributeNumber1,
|
Oid relationObjectId1, AttrNumber attributeNumber1,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: restrictinfo.h,v 1.6 1999/07/24 23:21:05 tgl Exp $
|
* $Id: restrictinfo.h,v 1.7 1999/07/25 23:07:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -17,10 +17,5 @@
|
|||||||
|
|
||||||
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
|
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
|
||||||
extern List *get_actual_clauses(List *restrictinfo_list);
|
extern List *get_actual_clauses(List *restrictinfo_list);
|
||||||
extern void get_relattvals(List *restrictinfo_list, List **attnos,
|
|
||||||
List **values, List **flags);
|
|
||||||
extern void get_joinvars(Oid relid, List *restrictinfo_list,
|
|
||||||
List **attnos, List **values, List **flags);
|
|
||||||
extern List *get_opnos(List *restrictinfo_list);
|
|
||||||
|
|
||||||
#endif /* RESTRICTINFO_H */
|
#endif /* RESTRICTINFO_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user