diff options
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 110 | ||||
-rw-r--r-- | src/backend/optimizer/path/orindxpath.c | 20 |
2 files changed, 88 insertions, 42 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 07b67a88228..bd0b09fcfe9 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.186 2005/07/02 23:00:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.187 2005/07/28 20:26:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -212,6 +212,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) * subclause to any index on x alone, because such a Path would already have * been generated at the upper level. So we could use an index on x,y,z * or an index on x,y for the OR subclause, but not an index on just x. + * When dealing with a partial index, a match of the index predicate to + * one of the "current" clauses also makes the index usable. * * If istoplevel is true (indicating we are considering the top level of a * rel's restriction clauses), we will include indexes in the result that @@ -248,6 +250,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, List *restrictclauses; List *index_pathkeys; List *useful_pathkeys; + bool useful_predicate; + bool found_clause; bool index_is_ordered; /* @@ -258,29 +262,60 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, * Otherwise, we have to test whether the added clauses are * sufficient to imply the predicate. If so, we could use * the index in the current context. + * + * We set useful_predicate to true iff the predicate was proven + * using the current set of clauses. This is needed to prevent + * matching a predOK index to an arm of an OR, which would be + * a legal but pointlessly inefficient plan. (A better plan will + * be generated by just scanning the predOK index alone, no OR.) */ - if (index->indpred != NIL && !index->predOK) + useful_predicate = false; + if (index->indpred != NIL) { - if (istoplevel) - continue; /* no point in trying to prove it */ + if (index->predOK) + { + if (istoplevel) + { + /* we know predicate was proven from these clauses */ + useful_predicate = true; + } + } + else + { + if (istoplevel) + continue; /* no point in trying to prove it */ - /* Form all_clauses if not done already */ - if (all_clauses == NIL) - all_clauses = list_concat(list_copy(clauses), - outer_clauses); + /* Form all_clauses if not done already */ + if (all_clauses == NIL) + all_clauses = list_concat(list_copy(clauses), + outer_clauses); - if (!predicate_implied_by(index->indpred, all_clauses) || - predicate_implied_by(index->indpred, outer_clauses)) - continue; + if (!predicate_implied_by(index->indpred, all_clauses)) + continue; /* can't use it at all */ + + if (!predicate_implied_by(index->indpred, outer_clauses)) + useful_predicate = true; + } } /* * 1. Match the index against the available restriction clauses. + * found_clause is set true only if at least one of the current + * clauses was used. */ restrictclauses = group_clauses_by_indexkey(index, clauses, outer_clauses, - outer_relids); + outer_relids, + &found_clause); + + /* + * Not all index AMs support scans with no restriction clauses. + * We can't generate a scan over an index with amoptionalkey = false + * unless there's at least one restriction clause. + */ + if (restrictclauses == NIL && !index->amoptionalkey) + continue; /* * 2. Compute pathkeys describing index's ordering, if any, then @@ -300,20 +335,12 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel, /* * 3. Generate an indexscan path if there are relevant restriction - * clauses OR the index ordering is potentially useful for later - * merging or final output ordering. - * - * If there is a predicate, consider it anyway since the index - * predicate has already been found to match the query. The - * selectivity of the predicate might alone make the index useful. - * - * Note: not all index AMs support scans with no restriction clauses. - * We can't generate a scan over an index with amoptionalkey = false - * unless there's at least one restriction clause. + * clauses in the current clauses, OR the index ordering is + * potentially useful for later merging or final output ordering, + * OR the index has a predicate that was proven by the current + * clauses. */ - if (restrictclauses != NIL || - (index->amoptionalkey && - (useful_pathkeys != NIL || index->indpred != NIL))) + if (found_clause || useful_pathkeys != NIL || useful_predicate) { ipath = create_index_path(root, index, restrictclauses, @@ -627,10 +654,9 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths) * with one index key (in no particular order); the top list is ordered by * index key. (This is depended on by expand_indexqual_conditions().) * - * As explained in the comments for find_usable_indexes(), we can use - * clauses from either of the given lists, but the result is required to - * use at least one clause from the "current clauses" list. We return - * NIL if we don't find any such clause. + * We can use clauses from either the current clauses or outer_clauses lists, + * but *found_clause is set TRUE only if we used at least one clause from + * the "current clauses" list. See find_usable_indexes() for motivation. * * outer_relids determines what Vars will be allowed on the other side * of a possible index qual; see match_clause_to_indexcol(). @@ -643,18 +669,25 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths) * Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4)) * if we find that clauses C1 and C2 use column A, clauses C3 and C4 use * column C, and no clauses use column B. + * + * Note: in some circumstances we may find the same RestrictInfos coming + * from multiple places. Defend against redundant outputs by using + * list_append_unique_ptr (pointer equality should be good enough). */ List * group_clauses_by_indexkey(IndexOptInfo *index, List *clauses, List *outer_clauses, - Relids outer_relids) + Relids outer_relids, + bool *found_clause) { List *clausegroup_list = NIL; - bool found_clause = false; + bool found_outer_clause = false; int indexcol = 0; Oid *classes = index->classlist; - if (clauses == NIL) + *found_clause = false; /* default result */ + + if (clauses == NIL && outer_clauses == NIL) return NIL; /* cannot succeed */ do @@ -675,8 +708,8 @@ group_clauses_by_indexkey(IndexOptInfo *index, rinfo, outer_relids)) { - clausegroup = lappend(clausegroup, rinfo); - found_clause = true; + clausegroup = list_append_unique_ptr(clausegroup, rinfo); + *found_clause = true; } } @@ -691,7 +724,10 @@ group_clauses_by_indexkey(IndexOptInfo *index, curClass, rinfo, outer_relids)) - clausegroup = lappend(clausegroup, rinfo); + { + clausegroup = list_append_unique_ptr(clausegroup, rinfo); + found_outer_clause = true; + } } /* @@ -707,8 +743,8 @@ group_clauses_by_indexkey(IndexOptInfo *index, } while (!DoneMatchingIndexKeys(classes)); - if (!found_clause) - return NIL; + if (!*found_clause && !found_outer_clause) + return NIL; /* no indexable clauses anywhere */ return clausegroup_list; } diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index 884329edd97..eb1e1a6ffcd 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.73 2005/07/02 23:00:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.74 2005/07/28 20:26:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -134,14 +134,24 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) return false; /* - * Convert the path's indexclauses structure to a RestrictInfo tree, - * and add it to the rel's restriction list. + * Convert the path's indexclauses structure to a RestrictInfo tree. + * We include any partial-index predicates so as to get a reasonable + * representation of what the path is actually scanning. */ - newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, true); - Assert(list_length(newrinfos) == 1); + newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, + true, true); + + /* It's possible we get back something other than a single OR clause */ + if (list_length(newrinfos) != 1) + return false; or_rinfo = (RestrictInfo *) linitial(newrinfos); Assert(IsA(or_rinfo, RestrictInfo)); + if (!restriction_is_or_clause(or_rinfo)) + return false; + /* + * OK, add it to the rel's restriction list. + */ rel->baserestrictinfo = list_concat(rel->baserestrictinfo, newrinfos); /* |