88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.62 2003/12/29 21:44:49 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.63 2004/01/04 03:51:52 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -54,33 +54,13 @@ static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
5454 *ROUTINES TO COMPUTE SELECTIVITIES
5555 ****************************************************************************/
5656
57- /*
58- * restrictlist_selectivity -
59- * Compute the selectivity of an implicitly-ANDed list of RestrictInfo
60- * clauses.
61- *
62- * This is the same as clauselist_selectivity except for the representation
63- * of the clause list.
64- */
65- Selectivity
66- restrictlist_selectivity (Query * root ,
67- List * restrictinfo_list ,
68- int varRelid ,
69- JoinType jointype )
70- {
71- List * clauselist = get_actual_clauses (restrictinfo_list );
72- Selectivity result ;
73-
74- result = clauselist_selectivity (root ,clauselist ,varRelid ,jointype );
75- freeList (clauselist );
76- return result ;
77- }
78-
7957/*
8058 * clauselist_selectivity -
8159 * Compute the selectivity of an implicitly-ANDed list of boolean
8260 * expression clauses. The list can be empty, in which case 1.0
83- * must be returned.
61+ * must be returned. List elements may be either RestrictInfos
62+ * or bare expression clauses --- the former is preferred since
63+ * it allows caching of results.
8464 *
8565 * See clause_selectivity() for the meaning of the additional parameters.
8666 *
@@ -133,64 +113,80 @@ clauselist_selectivity(Query *root,
133113foreach (clist ,clauses )
134114{
135115Node * clause = (Node * )lfirst (clist );
116+ RestrictInfo * rinfo ;
136117Selectivity s2 ;
137118
119+ /* Always compute the selectivity using clause_selectivity */
120+ s2 = clause_selectivity (root ,clause ,varRelid ,jointype );
121+
122+ /*
123+ * Check for being passed a RestrictInfo.
124+ */
125+ if (IsA (clause ,RestrictInfo ))
126+ {
127+ rinfo = (RestrictInfo * )clause ;
128+ clause = (Node * )rinfo -> clause ;
129+ }
130+ else
131+ rinfo = NULL ;
132+
138133/*
139134 * See if it looks like a restriction clause with a pseudoconstant
140135 * on one side. (Anything more complicated than that might not
141- * behave in the simple way we are expecting.)
142- *
143- * NB: for consistency of results, this fragment of code had better
144- * match what clause_selectivity() would do in the cases it
145- * handles.
136+ * behave in the simple way we are expecting.) Most of the tests
137+ * here can be done more efficiently with rinfo than without.
146138 */
147- if (is_opclause (clause )&&
148- (varRelid != 0 || NumRelids (clause )== 1 ))
139+ if (is_opclause (clause )&& length (((OpExpr * )clause )-> args )== 2 )
149140{
150141OpExpr * expr = (OpExpr * )clause ;
142+ bool varonleft = true;
143+ bool ok ;
151144
152- if (length ( expr -> args ) == 2 )
145+ if (rinfo )
153146{
154- bool varonleft = true;
147+ ok = (bms_membership (rinfo -> clause_relids )== BMS_SINGLETON )&&
148+ (is_pseudo_constant_clause_relids (lsecond (expr -> args ),
149+ rinfo -> right_relids )||
150+ (varonleft = false,
151+ is_pseudo_constant_clause_relids (lfirst (expr -> args ),
152+ rinfo -> left_relids )));
153+ }
154+ else
155+ {
156+ ok = (NumRelids (clause )== 1 )&&
157+ (is_pseudo_constant_clause (lsecond (expr -> args ))||
158+ (varonleft = false,
159+ is_pseudo_constant_clause (lfirst (expr -> args ))));
160+ }
155161
156- if (is_pseudo_constant_clause (lsecond (expr -> args ))||
157- (varonleft = false,
158- is_pseudo_constant_clause (lfirst (expr -> args ))))
162+ if (ok )
163+ {
164+ /*
165+ * If it's not a "<" or ">" operator, just merge the
166+ * selectivity in generically. But if it's the
167+ * right oprrest, add the clause to rqlist for later
168+ * processing.
169+ */
170+ switch (get_oprrest (expr -> opno ))
159171{
160- Oid opno = expr -> opno ;
161- RegProcedure oprrest = get_oprrest (opno );
162-
163- s2 = restriction_selectivity (root ,opno ,
164- expr -> args ,varRelid );
165-
166- /*
167- * If we reach here, we have computed the same result
168- * that clause_selectivity would, so we can just use
169- * s2 if it's the wrong oprrest. But if it's the
170- * right oprrest, add the clause to rqlist for later
171- * processing.
172- */
173- switch (oprrest )
174- {
175- case F_SCALARLTSEL :
176- addRangeClause (& rqlist ,clause ,
177- varonleft , true,s2 );
178- break ;
179- case F_SCALARGTSEL :
180- addRangeClause (& rqlist ,clause ,
181- varonleft , false,s2 );
182- break ;
183- default :
184- /* Just merge the selectivity in generically */
185- s1 = s1 * s2 ;
186- break ;
187- }
188- continue ;/* drop to loop bottom */
172+ case F_SCALARLTSEL :
173+ addRangeClause (& rqlist ,clause ,
174+ varonleft , true,s2 );
175+ break ;
176+ case F_SCALARGTSEL :
177+ addRangeClause (& rqlist ,clause ,
178+ varonleft , false,s2 );
179+ break ;
180+ default :
181+ /* Just merge the selectivity in generically */
182+ s1 = s1 * s2 ;
183+ break ;
189184}
185+ continue ;/* drop to loop bottom */
190186}
191187}
188+
192189/* Not the right form, so treat it generically. */
193- s2 = clause_selectivity (root ,clause ,varRelid ,jointype );
194190s1 = s1 * s2 ;
195191}
196192
@@ -352,11 +348,39 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause,
352348* rqlist = rqelem ;
353349}
354350
351+ /*
352+ * bms_is_subset_singleton
353+ *
354+ * Same result as bms_is_subset(s, bms_make_singleton(x)),
355+ * but a little faster and doesn't leak memory.
356+ *
357+ * Is this of use anywhere else? If so move to bitmapset.c ...
358+ */
359+ static bool
360+ bms_is_subset_singleton (const Bitmapset * s ,int x )
361+ {
362+ switch (bms_membership (s ))
363+ {
364+ case BMS_EMPTY_SET :
365+ return true;
366+ case BMS_SINGLETON :
367+ return bms_is_member (x ,s );
368+ case BMS_MULTIPLE :
369+ return false;
370+ }
371+ /* can't get here... */
372+ return false;
373+ }
374+
355375
356376/*
357377 * clause_selectivity -
358378 * Compute the selectivity of a general boolean expression clause.
359379 *
380+ * The clause can be either a RestrictInfo or a plain expression. If it's
381+ * a RestrictInfo, we try to cache the selectivity for possible re-use,
382+ * so passing RestrictInfos is preferred.
383+ *
360384 * varRelid is either 0 or a rangetable index.
361385 *
362386 * When varRelid is not 0, only variables belonging to that relation are
@@ -379,9 +403,37 @@ clause_selectivity(Query *root,
379403JoinType jointype )
380404{
381405Selectivity s1 = 1.0 ;/* default for any unhandled clause type */
406+ RestrictInfo * rinfo = NULL ;
407+ bool cacheable = false;
382408
383- if (clause == NULL )
409+ if (clause == NULL )/* can this still happen? */
384410return s1 ;
411+
412+ if (IsA (clause ,RestrictInfo ))
413+ {
414+ rinfo = (RestrictInfo * )clause ;
415+
416+ /*
417+ * If possible, cache the result of the selectivity calculation for
418+ * the clause. We can cache if varRelid is zero or the clause
419+ * contains only vars of that relid --- otherwise varRelid will affect
420+ * the result, so mustn't cache. We ignore the possibility that
421+ * jointype will affect the result, which should be okay because outer
422+ * join clauses will always be examined with the same jointype value.
423+ */
424+ if (varRelid == 0 ||
425+ bms_is_subset_singleton (rinfo -> clause_relids ,varRelid ))
426+ {
427+ /* Cacheable --- do we already have the result? */
428+ if (rinfo -> this_selec >=0 )
429+ return rinfo -> this_selec ;
430+ cacheable = true;
431+ }
432+
433+ /* Proceed with examination of contained clause */
434+ clause = (Node * )rinfo -> clause ;
435+ }
436+
385437if (IsA (clause ,Var ))
386438{
387439Var * var = (Var * )clause ;
@@ -448,9 +500,10 @@ clause_selectivity(Query *root,
448500else if (or_clause (clause ))
449501{
450502/*
451- * Selectivities for an 'or' clause are computed as s1+s2 - s1*s2
452- * to account for the probable overlap of selected tuple sets. XXX
453- * is this too conservative?
503+ * Selectivities for an OR clause are computed as s1+s2 - s1*s2
504+ * to account for the probable overlap of selected tuple sets.
505+ *
506+ * XXX is this too conservative?
454507 */
455508List * arg ;
456509
@@ -483,9 +536,13 @@ clause_selectivity(Query *root,
483536{
484537/*
485538 * Otherwise, it's a join if there's more than one relation
486- * used.
539+ * used. We can optimize this calculation if an rinfo was passed.
487540 */
488- is_join_clause = (NumRelids (clause )> 1 );
541+ if (rinfo )
542+ is_join_clause = (bms_membership (rinfo -> clause_relids )==
543+ BMS_MULTIPLE );
544+ else
545+ is_join_clause = (NumRelids (clause )> 1 );
489546}
490547
491548if (is_join_clause )
@@ -559,6 +616,10 @@ clause_selectivity(Query *root,
559616jointype );
560617}
561618
619+ /* Cache the result if possible */
620+ if (cacheable )
621+ rinfo -> this_selec = s1 ;
622+
562623#ifdef SELECTIVITY_DEBUG
563624elog (DEBUG4 ,"clause_selectivity: s1 %f" ,s1 );
564625#endif /* SELECTIVITY_DEBUG */