diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 08aee2010ef11a28f9823f05afe90a08de257b26..2a0c3d1c5d64b9373f152b343dabae645772e240 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.164 2004/08/29 05:06:43 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.165 2004/10/11 22:56:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,10 +64,9 @@ static bool match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index, RestrictInfo *rinfo); static Oid indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left); -static bool pred_test(List *predicate_list, List *restrictinfo_list); +static bool pred_test_recurse_pred(Expr *predicate, List *restrictinfo_list); static bool pred_test_restrict_list(Expr *predicate, List *restrictinfo_list); -static bool pred_test_recurse_clause(Expr *predicate, Node *clause); -static bool pred_test_recurse_pred(Expr *predicate, Node *clause); +static bool pred_test_recurse_restrict(Expr *predicate, Node *clause); static bool pred_test_simple_clause(Expr *predicate, Node *clause); static Relids indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index); static Path *make_innerjoin_index_path(Query *root, @@ -750,14 +749,13 @@ check_partial_indexes(Query *root, RelOptInfo *rel) * Recursively checks whether the clauses in restrictinfo_list imply * that the given predicate is true. * - * This routine (together with the routines it calls) iterates over - * ANDs in the predicate first, then reduces the qualification - * clauses down to their constituent terms, and iterates over ORs - * in the predicate last. This order is important to make the test - * succeed whenever possible (assuming the predicate has been converted - * to CNF format). --Nels, Jan '93 + * This routine (together with the routines it calls) first breaks down + * the predicate to its constituent AND/OR elements, then similarly + * breaks down the restriction clauses to AND/OR elements in an effort + * to prove that each predicate element is implied. The top-level + * List structure of each list corresponds to an AND list. */ -static bool +bool pred_test(List *predicate_list, List *restrictinfo_list) { ListCell *pred; @@ -785,10 +783,9 @@ pred_test(List *predicate_list, List *restrictinfo_list) { /* * if any clause is not implied, the whole predicate is not - * implied. Note we assume that any sub-ANDs have been flattened - * when the predicate was fed through canonicalize_qual(). + * implied. */ - if (!pred_test_restrict_list(lfirst(pred), restrictinfo_list)) + if (!pred_test_recurse_pred(lfirst(pred), restrictinfo_list)) return false; } return true; @@ -796,9 +793,53 @@ pred_test(List *predicate_list, List *restrictinfo_list) /* - * pred_test_restrict_list + * pred_test_recurse_pred * Does the "predicate inclusion test" for one conjunct of a predicate - * expression. + * expression. Here we recursively deal with the possibility that the + * predicate conjunct is itself an AND or OR structure. + */ +static bool +pred_test_recurse_pred(Expr *predicate, List *restrictinfo_list) +{ + List *items; + ListCell *item; + + Assert(predicate != NULL); + if (or_clause((Node *) predicate)) + { + items = ((BoolExpr *) predicate)->args; + foreach(item, items) + { + /* if any item is implied, the whole predicate is implied */ + if (pred_test_recurse_pred(lfirst(item), restrictinfo_list)) + return true; + } + return false; + } + else if (and_clause((Node *) predicate)) + { + items = ((BoolExpr *) predicate)->args; + foreach(item, items) + { + /* + * if any item is not implied, the whole predicate is not + * implied + */ + if (!pred_test_recurse_pred(lfirst(item), restrictinfo_list)) + return false; + } + return true; + } + else + return pred_test_restrict_list(predicate, restrictinfo_list); +} + + +/* + * pred_test_restrict_list + * Does the "predicate inclusion test" for one element of a predicate + * expression. Here we take care of the AND semantics of the top-level + * restrictinfo list. */ static bool pred_test_restrict_list(Expr *predicate, List *restrictinfo_list) @@ -809,9 +850,11 @@ pred_test_restrict_list(Expr *predicate, List *restrictinfo_list) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item); + Assert(IsA(restrictinfo, RestrictInfo)); + /* if any clause implies the predicate, return true */ - if (pred_test_recurse_clause(predicate, - (Node *) restrictinfo->clause)) + if (pred_test_recurse_restrict(predicate, + (Node *) restrictinfo->clause)) return true; } return false; @@ -819,13 +862,13 @@ pred_test_restrict_list(Expr *predicate, List *restrictinfo_list) /* - * pred_test_recurse_clause - * Does the "predicate inclusion test" for a general restriction-clause + * pred_test_recurse_restrict + * Does the "predicate inclusion test" for one element of a predicate * expression. Here we recursively deal with the possibility that the - * restriction clause is itself an AND or OR structure. + * restriction-list element is itself an AND or OR structure. */ static bool -pred_test_recurse_clause(Expr *predicate, Node *clause) +pred_test_recurse_restrict(Expr *predicate, Node *clause) { List *items; ListCell *item; @@ -837,7 +880,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause) foreach(item, items) { /* if any OR item doesn't imply the predicate, clause doesn't */ - if (!pred_test_recurse_clause(predicate, lfirst(item))) + if (!pred_test_recurse_restrict(predicate, lfirst(item))) return false; } return true; @@ -851,55 +894,11 @@ pred_test_recurse_clause(Expr *predicate, Node *clause) * if any AND item implies the predicate, the whole clause * does */ - if (pred_test_recurse_clause(predicate, lfirst(item))) + if (pred_test_recurse_restrict(predicate, lfirst(item))) return true; } return false; } - else - return pred_test_recurse_pred(predicate, clause); -} - - -/* - * pred_test_recurse_pred - * Does the "predicate inclusion test" for one conjunct of a predicate - * expression for a simple restriction clause. Here we recursively deal - * with the possibility that the predicate conjunct is itself an AND or - * OR structure. - */ -static bool -pred_test_recurse_pred(Expr *predicate, Node *clause) -{ - List *items; - ListCell *item; - - Assert(predicate != NULL); - if (or_clause((Node *) predicate)) - { - items = ((BoolExpr *) predicate)->args; - foreach(item, items) - { - /* if any item is implied, the whole predicate is implied */ - if (pred_test_recurse_pred(lfirst(item), clause)) - return true; - } - return false; - } - else if (and_clause((Node *) predicate)) - { - items = ((BoolExpr *) predicate)->args; - foreach(item, items) - { - /* - * if any item is not implied, the whole predicate is not - * implied - */ - if (!pred_test_recurse_pred(lfirst(item), clause)) - return false; - } - return true; - } else return pred_test_simple_clause(predicate, clause); } diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index c2de25aa4c6a39b80bb56bae780af10337a74c99..09c2aa161b620af6b8224825e9fe6df1d32951a9 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.62 2004/08/29 05:06:43 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.63 2004/10/11 22:56:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -355,15 +355,42 @@ best_or_subclause_index(Query *root, List *indexquals; Path subclause_path; - /* Ignore partial indexes that do not match the query */ + /* + * Ignore partial indexes that do not match the query. If predOK + * is true then the index's predicate is implied by top-level + * restriction clauses, so we can use it. However, it might also + * be implied by the current OR subclause (perhaps in conjunction + * with the top-level clauses), in which case we can use it for this + * particular scan. + * + * XXX this code is partially redundant with logic in + * group_clauses_by_indexkey_for_or(); consider refactoring. + */ if (index->indpred != NIL && !index->predOK) - continue; + { + List *subclauserinfos; + + if (and_clause((Node *) subclause)) + subclauserinfos = list_copy(((BoolExpr *) subclause)->args); + else if (IsA(subclause, RestrictInfo)) + subclauserinfos = list_make1(subclause); + else + continue; /* probably can't happen */ + if (!pred_test(index->indpred, + list_concat(subclauserinfos, + rel->baserestrictinfo))) + continue; + } /* Collect index clauses usable with this index */ indexclauses = group_clauses_by_indexkey_for_or(rel, index, subclause); - /* Ignore index if it doesn't match the subclause at all */ - if (indexclauses == NIL) + /* + * Ignore index if it doesn't match the subclause at all; except + * that if it's a partial index, consider it anyway, since the + * selectivity of the predicate alone might make the index useful. + */ + if (indexclauses == NIL && index->indpred == NIL) continue; /* Convert clauses to indexquals the executor can handle */ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index b9bfeddaa2ef560a0c50ff5b2f5aee0f8df826d5..845f6557613cc117367b789d978a973c4ddbff36 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.75 2004/08/29 05:06:57 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.76 2004/10/11 22:57:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,7 @@ extern List *group_clauses_by_indexkey_for_or(RelOptInfo *rel, extern List *expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups); extern void check_partial_indexes(Query *root, RelOptInfo *rel); +extern bool pred_test(List *predicate_list, List *restrictinfo_list); extern List *flatten_clausegroups_list(List *clausegroups); extern Expr *make_expr_from_indexclauses(List *indexclauses);