summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r--src/backend/optimizer/path/indxpath.c110
-rw-r--r--src/backend/optimizer/path/orindxpath.c20
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);
/*