diff options
Diffstat (limited to 'src/backend/optimizer/path/clausesel.c')
-rw-r--r-- | src/backend/optimizer/path/clausesel.c | 536 |
1 files changed, 294 insertions, 242 deletions
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 634e1130794..0ce580754e3 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * clausesel.c-- - * Routines to compute and set clause selectivities + * Routines to compute and set clause selectivities * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.2 1997/09/07 04:43:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,7 @@ #include "optimizer/cost.h" #include "optimizer/plancat.h" -#include "parser/parsetree.h" /* for getrelid() */ +#include "parser/parsetree.h" /* for getrelid() */ #include "catalog/pg_proc.h" #include "catalog/pg_operator.h" @@ -31,301 +31,353 @@ #include "utils/elog.h" #include "utils/lsyscache.h" -static Cost compute_selec(Query *root, List *clauses, List *or_selectivities); +static Cost compute_selec(Query * root, List * clauses, List * or_selectivities); /**************************************************************************** - * ROUTINES TO SET CLAUSE SELECTIVITIES + * ROUTINES TO SET CLAUSE SELECTIVITIES ****************************************************************************/ -/* +/* * set_clause_selectivities - - * Sets the selectivity field for each of clause in 'clauseinfo-list' - * to 'new-selectivity'. If the selectivity has already been set, reset - * it only if the new one is better. - * + * Sets the selectivity field for each of clause in 'clauseinfo-list' + * to 'new-selectivity'. If the selectivity has already been set, reset + * it only if the new one is better. + * * Returns nothing of interest. * */ void -set_clause_selectivities(List *clauseinfo_list, Cost new_selectivity) +set_clause_selectivities(List * clauseinfo_list, Cost new_selectivity) { - List *temp; - CInfo *clausenode; - Cost cost_clause; - - foreach (temp,clauseinfo_list) { - clausenode = (CInfo*)lfirst(temp); - cost_clause = clausenode->selectivity; - if ( FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) { - clausenode->selectivity = new_selectivity; + List *temp; + CInfo *clausenode; + Cost cost_clause; + + foreach(temp, clauseinfo_list) + { + clausenode = (CInfo *) lfirst(temp); + cost_clause = clausenode->selectivity; + if (FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) + { + clausenode->selectivity = new_selectivity; + } } - } } -/* +/* * product_selec - - * Multiplies the selectivities of each clause in 'clauseinfo-list'. - * + * Multiplies the selectivities of each clause in 'clauseinfo-list'. + * * Returns a flonum corresponding to the selectivity of 'clauseinfo-list'. */ Cost -product_selec(List *clauseinfo_list) +product_selec(List * clauseinfo_list) { - Cost result = 1.0; - if (clauseinfo_list!=NIL) { - List *xclausenode = NIL; - Cost temp; - - foreach(xclausenode,clauseinfo_list) { - temp = ((CInfo *)lfirst(xclausenode))->selectivity; - result = result * temp; + Cost result = 1.0; + + if (clauseinfo_list != NIL) + { + List *xclausenode = NIL; + Cost temp; + + foreach(xclausenode, clauseinfo_list) + { + temp = ((CInfo *) lfirst(xclausenode))->selectivity; + result = result * temp; + } } - } - return(result); + return (result); } -/* +/* * set_rest_relselec - - * Scans through clauses on each relation and assigns a selectivity to - * those clauses that haven't been assigned a selectivity by an index. - * + * Scans through clauses on each relation and assigns a selectivity to + * those clauses that haven't been assigned a selectivity by an index. + * * Returns nothing of interest. * MODIFIES: selectivities of the various rel's clauseinfo - * slots. + * slots. */ void -set_rest_relselec(Query *root, List *rel_list) +set_rest_relselec(Query * root, List * rel_list) { - Rel *rel; - List *x; + Rel *rel; + List *x; - foreach (x,rel_list) { - rel = (Rel*)lfirst(x); - set_rest_selec(root, rel->clauseinfo); - } + foreach(x, rel_list) + { + rel = (Rel *) lfirst(x); + set_rest_selec(root, rel->clauseinfo); + } } -/* +/* * set_rest_selec - - * Sets the selectivity fields for those clauses within a single - * relation's 'clauseinfo-list' that haven't already been set. - * + * Sets the selectivity fields for those clauses within a single + * relation's 'clauseinfo-list' that haven't already been set. + * * Returns nothing of interest. - * + * */ void -set_rest_selec(Query *root, List *clauseinfo_list) +set_rest_selec(Query * root, List * clauseinfo_list) { - List *temp = NIL; - CInfo *clausenode = (CInfo*)NULL; - Cost cost_clause; - - foreach (temp,clauseinfo_list) { - clausenode = (CInfo*)lfirst(temp); - cost_clause = clausenode->selectivity; + List *temp = NIL; + CInfo *clausenode = (CInfo *) NULL; + Cost cost_clause; - /* - * Check to see if the selectivity of this clause or any 'or' - * subclauses (if any) haven't been set yet. - */ - if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) { - clausenode->selectivity = - compute_clause_selec(root, - (Node*)clausenode->clause, - lcons(makeFloat(cost_clause), NIL)); + foreach(temp, clauseinfo_list) + { + clausenode = (CInfo *) lfirst(temp); + cost_clause = clausenode->selectivity; + + /* + * Check to see if the selectivity of this clause or any 'or' + * subclauses (if any) haven't been set yet. + */ + if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) + { + clausenode->selectivity = + compute_clause_selec(root, + (Node *) clausenode->clause, + lcons(makeFloat(cost_clause), NIL)); + } } - } } /**************************************************************************** - * ROUTINES TO COMPUTE SELECTIVITIES + * ROUTINES TO COMPUTE SELECTIVITIES ****************************************************************************/ -/* +/* * compute_clause_selec - - * Given a clause, this routine will compute the selectivity of the - * clause by calling 'compute_selec' with the appropriate parameters - * and possibly use that return value to compute the real selectivity - * of a clause. - * + * Given a clause, this routine will compute the selectivity of the + * clause by calling 'compute_selec' with the appropriate parameters + * and possibly use that return value to compute the real selectivity + * of a clause. + * * 'or-selectivities' are selectivities that have already been assigned - * to subclauses of an 'or' clause. - * + * to subclauses of an 'or' clause. + * * Returns a flonum corresponding to the clause selectivity. - * + * */ Cost -compute_clause_selec(Query *root, Node *clause, List *or_selectivities) +compute_clause_selec(Query * root, Node * clause, List * or_selectivities) { - if (!is_opclause (clause)) { - /* if it's not an operator clause, then it is a boolean clause -jolly*/ - /* - * Boolean variables get a selectivity of 1/2. - */ - return(0.1); - } else if (not_clause (clause)) { - /* - * 'not' gets "1.0 - selectivity-of-inner-clause". - */ - return (1.000000 - compute_selec(root, - lcons(get_notclausearg((Expr*)clause), - NIL), - or_selectivities)); - } else if (or_clause(clause)) { - /* - * Both 'or' and 'and' clauses are evaluated as described in - * (compute_selec). - */ - return (compute_selec(root, - ((Expr*)clause)->args, or_selectivities)); - } else { - return(compute_selec(root, - lcons(clause,NIL),or_selectivities)); - } + if (!is_opclause(clause)) + { + + /* + * if it's not an operator clause, then it is a boolean clause + * -jolly + */ + + /* + * Boolean variables get a selectivity of 1/2. + */ + return (0.1); + } + else if (not_clause(clause)) + { + + /* + * 'not' gets "1.0 - selectivity-of-inner-clause". + */ + return (1.000000 - compute_selec(root, + lcons(get_notclausearg((Expr *) clause), + NIL), + or_selectivities)); + } + else if (or_clause(clause)) + { + + /* + * Both 'or' and 'and' clauses are evaluated as described in + * (compute_selec). + */ + return (compute_selec(root, + ((Expr *) clause)->args, or_selectivities)); + } + else + { + return (compute_selec(root, + lcons(clause, NIL), or_selectivities)); + } } -/* - * compute_selec - - * Computes the selectivity of a clause. - * - * If there is more than one clause in the argument 'clauses', then the - * desired selectivity is that of an 'or' clause. Selectivities for an - * 'or' clause such as (OR a b) are computed by finding the selectivity - * of a (s1) and b (s2) and computing s1+s2 - s1*s2. - * - * In addition, if the clause is an 'or' clause, individual selectivities - * may have already been assigned by indices to subclauses. These values - * are contained in the list 'or-selectivities'. - * +/* + * compute_selec - + * Computes the selectivity of a clause. + * + * If there is more than one clause in the argument 'clauses', then the + * desired selectivity is that of an 'or' clause. Selectivities for an + * 'or' clause such as (OR a b) are computed by finding the selectivity + * of a (s1) and b (s2) and computing s1+s2 - s1*s2. + * + * In addition, if the clause is an 'or' clause, individual selectivities + * may have already been assigned by indices to subclauses. These values + * are contained in the list 'or-selectivities'. + * * Returns the clause selectivity as a flonum. - * + * */ -static Cost -compute_selec(Query *root, List *clauses, List *or_selectivities) +static Cost +compute_selec(Query * root, List * clauses, List * or_selectivities) { - Cost s1 = 0; - List *clause = lfirst(clauses); - - if (clauses==NULL) { - s1 = 1.0; - } else if (IsA(clause,Param)) { - /* XXX How're we handling this before?? -ay */ - s1 = 1.0; - } else if (IsA(clause,Const)) { - s1 = ((bool) ((Const*) clause)->constvalue) ? 1.0 : 0.0; - } else if (IsA(clause,Var)) { - Oid relid = getrelid(((Var*)clause)->varno, - root->rtable); + Cost s1 = 0; + List *clause = lfirst(clauses); - /* - * we have a bool Var. This is exactly equivalent to the clause: - * reln.attribute = 't' - * so we compute the selectivity as if that is what we have. The - * magic #define constants are a hack. I didn't want to have to - * do system cache look ups to find out all of that info. - */ + if (clauses == NULL) + { + s1 = 1.0; + } + else if (IsA(clause, Param)) + { + /* XXX How're we handling this before?? -ay */ + s1 = 1.0; + } + else if (IsA(clause, Const)) + { + s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0; + } + else if (IsA(clause, Var)) + { + Oid relid = getrelid(((Var *) clause)->varno, + root->rtable); - s1 = restriction_selectivity(EqualSelectivityProcedure, - BooleanEqualOperator, - relid, - ((Var*)clause)->varoattno, - "t", - _SELEC_CONSTANT_RIGHT_); - } else if (or_selectivities) { - /* If s1 has already been assigned by an index, use that value. */ - List *this_sel = lfirst(or_selectivities); - - s1 = floatVal(this_sel); - } else if (is_funcclause((Node*)clause)) { - /* this isn't an Oper, it's a Func!! */ - /* - ** This is not an operator, so we guess at the selectivity. - ** THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE - ** ABLE TO HAVE SELECTIVITIES THEMSELVES. - ** -- JMH 7/9/92 - */ - s1 = 0.1; - } else if (NumRelids((Node*) clause) == 1) { - /* ...otherwise, calculate s1 from 'clauses'. - * The clause is not a join clause, since there is - * only one relid in the clause. The clause - * selectivity will be based on the operator - * selectivity and operand values. - */ - Oid opno = ((Oper*)((Expr*)clause)->oper)->opno; - RegProcedure oprrest = get_oprrest(opno); - Oid relid; - int relidx; - AttrNumber attno; - Datum constval; - int flag; - - get_relattval((Node*)clause, &relidx, &attno, &constval, &flag); - relid = getrelid(relidx, root->rtable); - - /* if the oprrest procedure is missing for whatever reason, - use a selectivity of 0.5*/ - if (!oprrest) - s1 = (Cost) (0.5); + /* + * we have a bool Var. This is exactly equivalent to the clause: + * reln.attribute = 't' so we compute the selectivity as if that + * is what we have. The magic #define constants are a hack. I + * didn't want to have to do system cache look ups to find out all + * of that info. + */ + + s1 = restriction_selectivity(EqualSelectivityProcedure, + BooleanEqualOperator, + relid, + ((Var *) clause)->varoattno, + "t", + _SELEC_CONSTANT_RIGHT_); + } + else if (or_selectivities) + { + /* If s1 has already been assigned by an index, use that value. */ + List *this_sel = lfirst(or_selectivities); + + s1 = floatVal(this_sel); + } + else if (is_funcclause((Node *) clause)) + { + /* this isn't an Oper, it's a Func!! */ + + /* + * * This is not an operator, so we guess at the selectivity. * + * THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE * ABLE + * TO HAVE SELECTIVITIES THEMSELVES. * -- JMH 7/9/92 + */ + s1 = 0.1; + } + else if (NumRelids((Node *) clause) == 1) + { + + /* + * ...otherwise, calculate s1 from 'clauses'. The clause is not a + * join clause, since there is only one relid in the clause. The + * clause selectivity will be based on the operator selectivity + * and operand values. + */ + Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + RegProcedure oprrest = get_oprrest(opno); + Oid relid; + int relidx; + AttrNumber attno; + Datum constval; + int flag; + + get_relattval((Node *) clause, &relidx, &attno, &constval, &flag); + relid = getrelid(relidx, root->rtable); + + /* + * if the oprrest procedure is missing for whatever reason, use a + * selectivity of 0.5 + */ + if (!oprrest) + s1 = (Cost) (0.5); + else if (attno == InvalidAttrNumber) + { + + /* + * attno can be Invalid if the clause had a function in it, + * i.e. WHERE myFunc(f) = 10 + */ + /* this should be FIXED somehow to use function selectivity */ + s1 = (Cost) (0.5); + } + else + s1 = (Cost) restriction_selectivity(oprrest, + opno, + relid, + attno, + (char *) constval, + flag); + + } else - if (attno == InvalidAttrNumber) { - /* attno can be Invalid if the clause had a function in it, - i.e. WHERE myFunc(f) = 10 */ - /* this should be FIXED somehow to use function selectivity */ - s1 = (Cost) (0.5); - } else - s1 = (Cost) restriction_selectivity(oprrest, - opno, - relid, - attno, - (char *)constval, - flag); - - } else { - /* The clause must be a join clause. The clause - * selectivity will be based on the relations to be - * scanned and the attributes they are to be joined - * on. + { + + /* + * The clause must be a join clause. The clause selectivity will + * be based on the relations to be scanned and the attributes they + * are to be joined on. + */ + Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + RegProcedure oprjoin = get_oprjoin(opno); + int relid1, + relid2; + AttrNumber attno1, + attno2; + + get_rels_atts((Node *) 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 + * selectivity of 0.5 + */ + if (!oprjoin) + s1 = (Cost) (0.5); + else + s1 = (Cost) join_selectivity(oprjoin, + opno, + relid1, + attno1, + relid2, + attno2); + } + + /* + * A null clause list eliminates no tuples, so return a selectivity of + * 1.0. If there is only one clause, the selectivity is not that of + * an 'or' clause, but rather that of the single clause. */ - Oid opno = ((Oper*)((Expr*)clause)->oper)->opno; - RegProcedure oprjoin = get_oprjoin (opno); - int relid1, relid2; - AttrNumber attno1, attno2; - - get_rels_atts((Node*)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 selectivity of 0.5*/ - if (!oprjoin) - s1 = (Cost) (0.5); - else - s1 = (Cost) join_selectivity(oprjoin, - opno, - relid1, - attno1, - relid2, - attno2); - } - - /* A null clause list eliminates no tuples, so return a selectivity - * of 1.0. If there is only one clause, the selectivity is not - * that of an 'or' clause, but rather that of the single clause. - */ - - if (length (clauses) < 2) { - return(s1); - } else { - /* Compute selectivity of the 'or'ed subclauses. */ - /* Added check for taking lnext(NIL). -- JMH 3/9/92 */ - Cost s2; - - if (or_selectivities != NIL) - s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities)); + + if (length(clauses) < 2) + { + return (s1); + } else - s2 = compute_selec(root, lnext(clauses), NIL); - return(s1 + s2 - s1 * s2); - } -} + { + /* Compute selectivity of the 'or'ed subclauses. */ + /* Added check for taking lnext(NIL). -- JMH 3/9/92 */ + Cost s2; + if (or_selectivities != NIL) + s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities)); + else + s2 = compute_selec(root, lnext(clauses), NIL); + return (s1 + s2 - s1 * s2); + } +} |