1 /*-------------------------------------------------------------------------
4 * Routines to compute and set clause selectivities
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.21 1999/07/15 22:39:22 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "catalog/pg_operator.h"
17 #include "optimizer/clauses.h"
18 #include "optimizer/restrictinfo.h"
19 #include "optimizer/cost.h"
20 #include "optimizer/internal.h"
21 #include "optimizer/plancat.h"
22 #include "parser/parsetree.h" /* for getrelid() */
23 #include "utils/lsyscache.h"
26 static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
28 /****************************************************************************
29 * ROUTINES TO SET CLAUSE SELECTIVITIES
30 ****************************************************************************/
33 * set_clause_selectivities -
34 * Sets the selectivity field for each of clause in 'restrictinfo-list'
35 * to 'new-selectivity'. If the selectivity has already been set, reset
36 * it only if the new one is better.
38 * Returns nothing of interest.
42 set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
45 RestrictInfo *clausenode;
48 foreach(temp, restrictinfo_list)
50 clausenode = (RestrictInfo *) lfirst(temp);
51 cost_clause = clausenode->selectivity;
52 if (cost_clause <= 0 || new_selectivity < cost_clause)
53 clausenode->selectivity = new_selectivity;
59 * Multiplies the selectivities of each clause in 'restrictinfo-list'.
61 * Returns a flonum corresponding to the selectivity of 'restrictinfo-list'.
64 product_selec(List *restrictinfo_list)
68 if (restrictinfo_list != NIL)
70 List *xclausenode = NIL;
73 foreach(xclausenode, restrictinfo_list)
75 temp = ((RestrictInfo *) lfirst(xclausenode))->selectivity;
76 result = result * temp;
84 * Scans through clauses on each relation and assigns a selectivity to
85 * those clauses that haven't been assigned a selectivity by an index.
87 * Returns nothing of interest.
88 * MODIFIES: selectivities of the various rel's restrictinfo
92 set_rest_relselec(Query *root, List *rel_list)
99 rel = (RelOptInfo *) lfirst(x);
100 set_rest_selec(root, rel->restrictinfo);
106 * Sets the selectivity fields for those clauses within a single
107 * relation's 'restrictinfo-list' that haven't already been set.
109 * Returns nothing of interest.
113 set_rest_selec(Query *root, List *restrictinfo_list)
116 RestrictInfo *clausenode = (RestrictInfo *) NULL;
119 foreach(temp, restrictinfo_list)
121 clausenode = (RestrictInfo *) lfirst(temp);
122 cost_clause = clausenode->selectivity;
125 * Check to see if the selectivity of this clause or any 'or'
126 * subclauses (if any) haven't been set yet.
128 if (cost_clause <= 0 || valid_or_clause(clausenode))
130 clausenode->selectivity = compute_clause_selec(root,
131 (Node *) clausenode->clause,
132 lcons(makeFloat(cost_clause), NIL));
137 /****************************************************************************
138 * ROUTINES TO COMPUTE SELECTIVITIES
139 ****************************************************************************/
142 * compute_clause_selec -
143 * Given a clause, this routine will compute the selectivity of the
144 * clause by calling 'compute_selec' with the appropriate parameters
145 * and possibly use that return value to compute the real selectivity
148 * 'or-selectivities' are selectivities that have already been assigned
149 * to subclauses of an 'or' clause.
151 * Returns a flonum corresponding to the clause selectivity.
155 compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
157 if (is_opclause(clause))
158 return compute_selec(root, lcons(clause, NIL), or_selectivities);
159 else if (not_clause(clause))
163 * 'not' gets "1.0 - selectivity-of-inner-clause".
165 return (1.000000 - compute_selec(root,
166 lcons(get_notclausearg((Expr *) clause),
170 else if (or_clause(clause))
174 * Both 'or' and 'and' clauses are evaluated as described in
177 return compute_selec(root, ((Expr *) clause)->args, or_selectivities);
180 return compute_selec(root, lcons(clause, NIL), or_selectivities);
185 * Computes the selectivity of a clause.
187 * If there is more than one clause in the argument 'clauses', then the
188 * desired selectivity is that of an 'or' clause. Selectivities for an
189 * 'or' clause such as (OR a b) are computed by finding the selectivity
190 * of a (s1) and b (s2) and computing s1+s2 - s1*s2.
192 * In addition, if the clause is an 'or' clause, individual selectivities
193 * may have already been assigned by indices to subclauses. These values
194 * are contained in the list 'or-selectivities'.
196 * Returns the clause selectivity as a flonum.
200 compute_selec(Query *root, List *clauses, List *or_selectivities)
203 List *clause = lfirst(clauses);
207 else if (IsA(clause, Param))
209 /* XXX How're we handling this before?? -ay */
212 else if (IsA(clause, Const))
213 s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
214 else if (IsA(clause, Var))
216 Oid relid = getrelid(((Var *) clause)->varno,
220 * we have a bool Var. This is exactly equivalent to the clause:
221 * reln.attribute = 't' so we compute the selectivity as if that
222 * is what we have. The magic #define constants are a hack. I
223 * didn't want to have to do system cache look ups to find out all
227 s1 = restriction_selectivity(F_EQSEL,
228 BooleanEqualOperator,
230 ((Var *) clause)->varoattno,
232 _SELEC_CONSTANT_RIGHT_);
234 else if (or_selectivities)
236 /* If s1 has already been assigned by an index, use that value. */
237 List *this_sel = lfirst(or_selectivities);
239 s1 = floatVal(this_sel);
241 else if (is_funcclause((Node *) clause))
243 /* this isn't an Oper, it's a Func!! */
246 * This is not an operator, so we guess at the selectivity. THIS
247 * IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE ABLE TO HAVE
248 * SELECTIVITIES THEMSELVES. -- JMH 7/9/92
252 else if (not_clause((Node *) clause))
254 /* negate this baby */
255 return 1 - compute_selec(root, ((Expr *) clause)->args, or_selectivities);
257 else if (is_subplan((Node *) clause))
261 * Just for the moment! FIX ME! - vadim 02/04/98
265 else if (NumRelids((Node *) clause) == 1)
269 * ...otherwise, calculate s1 from 'clauses'. The clause is not a
270 * join clause, since there is only one relid in the clause. The
271 * clause selectivity will be based on the operator selectivity
272 * and operand values.
274 Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
275 RegProcedure oprrest = get_oprrest(opno);
282 get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
283 relid = getrelid(relidx, root->rtable);
286 * if the oprrest procedure is missing for whatever reason, use a
291 else if (attno == InvalidAttrNumber)
295 * attno can be Invalid if the clause had a function in it,
296 * i.e. WHERE myFunc(f) = 10
298 /* this should be FIXED somehow to use function selectivity */
302 s1 = (Cost) restriction_selectivity(oprrest,
314 * The clause must be a join clause. The clause selectivity will
315 * be based on the relations to be scanned and the attributes they
316 * are to be joined on.
318 Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
319 RegProcedure oprjoin = get_oprjoin(opno);
325 get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
326 relid1 = getrelid(relid1, root->rtable);
327 relid2 = getrelid(relid2, root->rtable);
330 * if the oprjoin procedure is missing for whatever reason, use a
336 s1 = (Cost) join_selectivity(oprjoin,
345 * A null clause list eliminates no tuples, so return a selectivity of
346 * 1.0. If there is only one clause, the selectivity is not that of
347 * an 'or' clause, but rather that of the single clause.
350 if (lnext(clauses) == NIL)
354 /* Compute selectivity of the 'or'ed subclauses. */
355 /* Added check for taking lnext(NIL). -- JMH 3/9/92 */
358 if (or_selectivities != NIL)
359 s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
361 s2 = compute_selec(root, lnext(clauses), NIL);
362 return s1 + s2 - s1 * s2;