8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -54,33 +54,13 @@ static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
54
54
* ROUTINES TO COMPUTE SELECTIVITIES
55
55
****************************************************************************/
56
56
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
-
79
57
/*
80
58
* clauselist_selectivity -
81
59
* Compute the selectivity of an implicitly-ANDed list of boolean
82
60
* 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.
84
64
*
85
65
* See clause_selectivity() for the meaning of the additional parameters.
86
66
*
@@ -133,64 +113,80 @@ clauselist_selectivity(Query *root,
133
113
foreach (clist , clauses )
134
114
{
135
115
Node * clause = (Node * ) lfirst (clist );
116
+ RestrictInfo * rinfo ;
136
117
Selectivity s2 ;
137
118
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
+
138
133
/*
139
134
* See if it looks like a restriction clause with a pseudoconstant
140
135
* 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.
146
138
*/
147
- if (is_opclause (clause ) &&
148
- (varRelid != 0 || NumRelids (clause ) == 1 ))
139
+ if (is_opclause (clause ) && length (((OpExpr * ) clause )-> args ) == 2 )
149
140
{
150
141
OpExpr * expr = (OpExpr * ) clause ;
142
+ bool varonleft = true;
143
+ bool ok ;
151
144
152
- if (length ( expr -> args ) == 2 )
145
+ if (rinfo )
153
146
{
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
+ }
155
161
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 ))
159
171
{
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 ;
189
184
}
185
+ continue ; /* drop to loop bottom */
190
186
}
191
187
}
188
+
192
189
/* Not the right form, so treat it generically. */
193
- s2 = clause_selectivity (root , clause , varRelid , jointype );
194
190
s1 = s1 * s2 ;
195
191
}
196
192
@@ -352,11 +348,39 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause,
352
348
* rqlist = rqelem ;
353
349
}
354
350
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
+
355
375
356
376
/*
357
377
* clause_selectivity -
358
378
* Compute the selectivity of a general boolean expression clause.
359
379
*
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
+ *
360
384
* varRelid is either 0 or a rangetable index.
361
385
*
362
386
* When varRelid is not 0, only variables belonging to that relation are
@@ -379,9 +403,37 @@ clause_selectivity(Query *root,
379
403
JoinType jointype )
380
404
{
381
405
Selectivity s1 = 1.0 ; /* default for any unhandled clause type */
406
+ RestrictInfo * rinfo = NULL ;
407
+ bool cacheable = false;
382
408
383
- if (clause == NULL )
409
+ if (clause == NULL ) /* can this still happen? */
384
410
return 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
+
385
437
if (IsA (clause , Var ))
386
438
{
387
439
Var * var = (Var * ) clause ;
@@ -448,9 +500,10 @@ clause_selectivity(Query *root,
448
500
else if (or_clause (clause ))
449
501
{
450
502
/*
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?
454
507
*/
455
508
List * arg ;
456
509
@@ -483,9 +536,13 @@ clause_selectivity(Query *root,
483
536
{
484
537
/*
485
538
* 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.
487
540
*/
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 );
489
546
}
490
547
491
548
if (is_join_clause )
@@ -559,6 +616,10 @@ clause_selectivity(Query *root,
559
616
jointype );
560
617
}
561
618
619
+ /* Cache the result if possible */
620
+ if (cacheable )
621
+ rinfo -> this_selec = s1 ;
622
+
562
623
#ifdef SELECTIVITY_DEBUG
563
624
elog (DEBUG4 , "clause_selectivity: s1 %f" , s1 );
564
625
#endif /* SELECTIVITY_DEBUG */
0 commit comments