9
9
*
10
10
*
11
11
* IDENTIFICATION
12
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.186 2005/07/02 23:00:40 tgl Exp $
12
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.187 2005/07/28 20:26:20 tgl Exp $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
@@ -212,6 +212,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
212
212
* subclause to any index on x alone, because such a Path would already have
213
213
* been generated at the upper level. So we could use an index on x,y,z
214
214
* or an index on x,y for the OR subclause, but not an index on just x.
215
+ * When dealing with a partial index, a match of the index predicate to
216
+ * one of the "current" clauses also makes the index usable.
215
217
*
216
218
* If istoplevel is true (indicating we are considering the top level of a
217
219
* rel's restriction clauses), we will include indexes in the result that
@@ -248,6 +250,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
248
250
List * restrictclauses ;
249
251
List * index_pathkeys ;
250
252
List * useful_pathkeys ;
253
+ bool useful_predicate ;
254
+ bool found_clause ;
251
255
bool index_is_ordered ;
252
256
253
257
/*
@@ -258,29 +262,60 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
258
262
* Otherwise, we have to test whether the added clauses are
259
263
* sufficient to imply the predicate. If so, we could use
260
264
* the index in the current context.
265
+ *
266
+ * We set useful_predicate to true iff the predicate was proven
267
+ * using the current set of clauses. This is needed to prevent
268
+ * matching a predOK index to an arm of an OR, which would be
269
+ * a legal but pointlessly inefficient plan. (A better plan will
270
+ * be generated by just scanning the predOK index alone, no OR.)
261
271
*/
262
- if (index -> indpred != NIL && !index -> predOK )
272
+ useful_predicate = false;
273
+ if (index -> indpred != NIL )
263
274
{
264
- if (istoplevel )
265
- continue ; /* no point in trying to prove it */
275
+ if (index -> predOK )
276
+ {
277
+ if (istoplevel )
278
+ {
279
+ /* we know predicate was proven from these clauses */
280
+ useful_predicate = true;
281
+ }
282
+ }
283
+ else
284
+ {
285
+ if (istoplevel )
286
+ continue ; /* no point in trying to prove it */
266
287
267
- /* Form all_clauses if not done already */
268
- if (all_clauses == NIL )
269
- all_clauses = list_concat (list_copy (clauses ),
270
- outer_clauses );
288
+ /* Form all_clauses if not done already */
289
+ if (all_clauses == NIL )
290
+ all_clauses = list_concat (list_copy (clauses ),
291
+ outer_clauses );
271
292
272
- if (!predicate_implied_by (index -> indpred , all_clauses ) ||
273
- predicate_implied_by (index -> indpred , outer_clauses ))
274
- continue ;
293
+ if (!predicate_implied_by (index -> indpred , all_clauses ))
294
+ continue ; /* can't use it at all */
295
+
296
+ if (!predicate_implied_by (index -> indpred , outer_clauses ))
297
+ useful_predicate = true;
298
+ }
275
299
}
276
300
277
301
/*
278
302
* 1. Match the index against the available restriction clauses.
303
+ * found_clause is set true only if at least one of the current
304
+ * clauses was used.
279
305
*/
280
306
restrictclauses = group_clauses_by_indexkey (index ,
281
307
clauses ,
282
308
outer_clauses ,
283
- outer_relids );
309
+ outer_relids ,
310
+ & found_clause );
311
+
312
+ /*
313
+ * Not all index AMs support scans with no restriction clauses.
314
+ * We can't generate a scan over an index with amoptionalkey = false
315
+ * unless there's at least one restriction clause.
316
+ */
317
+ if (restrictclauses == NIL && !index -> amoptionalkey )
318
+ continue ;
284
319
285
320
/*
286
321
* 2. Compute pathkeys describing index's ordering, if any, then
@@ -300,20 +335,12 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
300
335
301
336
/*
302
337
* 3. Generate an indexscan path if there are relevant restriction
303
- * clauses OR the index ordering is potentially useful for later
304
- * merging or final output ordering.
305
- *
306
- * If there is a predicate, consider it anyway since the index
307
- * predicate has already been found to match the query. The
308
- * selectivity of the predicate might alone make the index useful.
309
- *
310
- * Note: not all index AMs support scans with no restriction clauses.
311
- * We can't generate a scan over an index with amoptionalkey = false
312
- * unless there's at least one restriction clause.
338
+ * clauses in the current clauses, OR the index ordering is
339
+ * potentially useful for later merging or final output ordering,
340
+ * OR the index has a predicate that was proven by the current
341
+ * clauses.
313
342
*/
314
- if (restrictclauses != NIL ||
315
- (index -> amoptionalkey &&
316
- (useful_pathkeys != NIL || index -> indpred != NIL )))
343
+ if (found_clause || useful_pathkeys != NIL || useful_predicate )
317
344
{
318
345
ipath = create_index_path (root , index ,
319
346
restrictclauses ,
@@ -627,10 +654,9 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
627
654
* with one index key (in no particular order); the top list is ordered by
628
655
* index key. (This is depended on by expand_indexqual_conditions().)
629
656
*
630
- * As explained in the comments for find_usable_indexes(), we can use
631
- * clauses from either of the given lists, but the result is required to
632
- * use at least one clause from the "current clauses" list. We return
633
- * NIL if we don't find any such clause.
657
+ * We can use clauses from either the current clauses or outer_clauses lists,
658
+ * but *found_clause is set TRUE only if we used at least one clause from
659
+ * the "current clauses" list. See find_usable_indexes() for motivation.
634
660
*
635
661
* outer_relids determines what Vars will be allowed on the other side
636
662
* of a possible index qual; see match_clause_to_indexcol().
@@ -643,18 +669,25 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
643
669
* Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4))
644
670
* if we find that clauses C1 and C2 use column A, clauses C3 and C4 use
645
671
* column C, and no clauses use column B.
672
+ *
673
+ * Note: in some circumstances we may find the same RestrictInfos coming
674
+ * from multiple places. Defend against redundant outputs by using
675
+ * list_append_unique_ptr (pointer equality should be good enough).
646
676
*/
647
677
List *
648
678
group_clauses_by_indexkey (IndexOptInfo * index ,
649
679
List * clauses , List * outer_clauses ,
650
- Relids outer_relids )
680
+ Relids outer_relids ,
681
+ bool * found_clause )
651
682
{
652
683
List * clausegroup_list = NIL ;
653
- bool found_clause = false;
684
+ bool found_outer_clause = false;
654
685
int indexcol = 0 ;
655
686
Oid * classes = index -> classlist ;
656
687
657
- if (clauses == NIL )
688
+ * found_clause = false; /* default result */
689
+
690
+ if (clauses == NIL && outer_clauses == NIL )
658
691
return NIL ; /* cannot succeed */
659
692
660
693
do
@@ -675,8 +708,8 @@ group_clauses_by_indexkey(IndexOptInfo *index,
675
708
rinfo ,
676
709
outer_relids ))
677
710
{
678
- clausegroup = lappend (clausegroup , rinfo );
679
- found_clause = true;
711
+ clausegroup = list_append_unique_ptr (clausegroup , rinfo );
712
+ * found_clause = true;
680
713
}
681
714
}
682
715
@@ -691,7 +724,10 @@ group_clauses_by_indexkey(IndexOptInfo *index,
691
724
curClass ,
692
725
rinfo ,
693
726
outer_relids ))
694
- clausegroup = lappend (clausegroup , rinfo );
727
+ {
728
+ clausegroup = list_append_unique_ptr (clausegroup , rinfo );
729
+ found_outer_clause = true;
730
+ }
695
731
}
696
732
697
733
/*
@@ -707,8 +743,8 @@ group_clauses_by_indexkey(IndexOptInfo *index,
707
743
708
744
} while (!DoneMatchingIndexKeys (classes ));
709
745
710
- if (!found_clause )
711
- return NIL ;
746
+ if (!* found_clause && ! found_outer_clause )
747
+ return NIL ; /* no indexable clauses anywhere */
712
748
713
749
return clausegroup_list ;
714
750
}
0 commit comments