OSDN Git Service

Further cleanup for OR-of-AND WHERE-clauses. orindxpath can now handle
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Feb 2000 18:26:09 +0000 (18:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Feb 2000 18:26:09 +0000 (18:26 +0000)
extracting from an AND subclause just those opclauses that are relevant
for a particular index.  For example, we can now consider using an index
on x to process WHERE (x = 1 AND y = 2) OR (x = 2 AND y = 4) OR ...

src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/orindxpath.c
src/include/optimizer/paths.h

index 8dd9117..4c2b010 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.78 2000/01/26 05:56:34 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.79 2000/02/05 18:26:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,15 +51,12 @@ typedef enum {
 } Prefix_Status;
 
 static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
-                                                                 int indexkey, Oid opclass,
                                                                  List *restrictinfo_list);
 static List *match_index_orclause(RelOptInfo *rel, IndexOptInfo *index,
-                                                                 int indexkey, Oid opclass,
                                                                  List *or_clauses,
                                                                  List *other_matching_indices);
 static bool match_or_subclause_to_indexkey(RelOptInfo *rel,
                                                                                   IndexOptInfo *index,
-                                                                                  int indexkey, Oid opclass,
                                                                                   Expr *clause);
 static List *group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index,
                                                                           int *indexkeys, Oid *classes,
@@ -174,20 +171,11 @@ create_index_paths(Query *root,
                 * so we can't build a path for an 'or' clause until all indexes have
                 * been matched against it.)
                 *
-                * We currently only look to match the first key of each index against
-                * 'or' subclauses.  There are cases where a later key of a multi-key
-                * index could be used (if other top-level clauses match earlier keys
-                * of the index), but our poor brains are hurting already...
-                *
                 * We don't even think about special handling of 'or' clauses that
                 * involve more than one relation (ie, are join clauses).
                 * Can we do anything useful with those?
                 */
-               match_index_orclauses(rel,
-                                                         index,
-                                                         index->indexkeys[0],
-                                                         index->classlist[0],
-                                                         restrictinfo_list);
+               match_index_orclauses(rel, index, restrictinfo_list);
 
                /*
                 * 2. If the keys of this index match any of the available non-'or'
@@ -267,15 +255,11 @@ create_index_paths(Query *root,
  *
  * 'rel' is the node of the relation on which the index is defined.
  * 'index' is the index node.
- * 'indexkey' is the (single) key of the index that we will consider.
- * 'class' is the class of the operator corresponding to 'indexkey'.
  * 'restrictinfo_list' is the list of available restriction clauses.
  */
 static void
 match_index_orclauses(RelOptInfo *rel,
                                          IndexOptInfo *index,
-                                         int indexkey,
-                                         Oid opclass,
                                          List *restrictinfo_list)
 {
        List       *i;
@@ -292,7 +276,6 @@ match_index_orclauses(RelOptInfo *rel,
                         */
                        restrictinfo->subclauseindices =
                                match_index_orclause(rel, index,
-                                                                        indexkey, opclass,
                                                                         restrictinfo->clause->args,
                                                                         restrictinfo->subclauseindices);
                }
@@ -305,9 +288,12 @@ match_index_orclauses(RelOptInfo *rel,
  *
  *       A match means that:
  *       (1) the operator within the subclause can be used with the
- *                             index's specified operator class, and
+ *               index's specified operator class, and
  *       (2) one operand of the subclause matches the index key.
  *
+ *       If a subclause is an 'and' clause, then it matches if any of its
+ *       subclauses is an opclause that matches.
+ *
  * 'or_clauses' is the list of subclauses within the 'or' clause
  * 'other_matching_indices' is the list of information on other indices
  *             that have already been matched to subclauses within this
@@ -323,8 +309,6 @@ match_index_orclauses(RelOptInfo *rel,
 static List *
 match_index_orclause(RelOptInfo *rel,
                                         IndexOptInfo *index,
-                                        int indexkey,
-                                        Oid opclass,
                                         List *or_clauses,
                                         List *other_matching_indices)
 {
@@ -350,8 +334,7 @@ match_index_orclause(RelOptInfo *rel,
        {
                Expr       *clause = lfirst(clist);
 
-               if (match_or_subclause_to_indexkey(rel, index, indexkey, opclass,
-                                                                                  clause))
+               if (match_or_subclause_to_indexkey(rel, index, clause))
                {
                        /* OK to add this index to sublist for this subclause */
                        lfirst(matching_indices) = lcons(index,
@@ -368,33 +351,84 @@ match_index_orclause(RelOptInfo *rel,
  * See if a subclause of an OR clause matches an index.
  *
  * We accept the subclause if it is an operator clause that matches the
- * index, or if it is an AND clause all of whose members are operators
- * that match the index.  (XXX Would accepting a single match be useful?)
+ * index, or if it is an AND clause any of whose members is an opclause
+ * that matches the index.
+ *
+ * We currently only look to match the first key of an index against
+ * 'or' subclauses.  There are cases where a later key of a multi-key
+ * index could be used (if other top-level clauses match earlier keys
+ * of the index), but our poor brains are hurting already...
  */
 static bool
 match_or_subclause_to_indexkey(RelOptInfo *rel,
                                                           IndexOptInfo *index,
-                                                          int indexkey,
-                                                          Oid opclass,
                                                           Expr *clause)
 {
+       int             indexkey = index->indexkeys[0];
+       Oid             opclass = index->classlist[0];
+
        if (and_clause((Node *) clause))
        {
                List       *item;
 
                foreach(item, clause->args)
                {
-                       if (match_clause_to_indexkey(rel, index, indexkey, opclass,
-                                                                                  lfirst(item), false))
-                               return false;
+                       if (match_clause_to_indexkey(rel, index, indexkey, opclass,
+                                                                                lfirst(item), false))
+                               return true;
                }
-               return true;
+               return false;
        }
        else
                return match_clause_to_indexkey(rel, index, indexkey, opclass,
                                                                                clause, false);
 }
 
+/*
+ * Given an OR subclause that has previously been determined to match
+ * the specified index, extract a list of specific opclauses that can be
+ * used as indexquals.
+ *
+ * In the simplest case this just means making a one-element list of the
+ * given opclause.  However, if the OR subclause is an AND, we have to
+ * scan it to find the opclause(s) that match the index.  (There should
+ * be at least one, if match_or_subclause_to_indexkey succeeded, but there
+ * could be more.)  Also, we apply expand_indexqual_conditions() to convert
+ * any special matching opclauses to indexable operators.
+ *
+ * The passed-in clause is not changed.
+ */
+List *
+extract_or_indexqual_conditions(RelOptInfo *rel,
+                                                               IndexOptInfo *index,
+                                                               Expr *orsubclause)
+{
+       List   *quals = NIL;
+       int             indexkey = index->indexkeys[0];
+       Oid             opclass = index->classlist[0];
+
+       if (and_clause((Node *) orsubclause))
+       {
+               List       *item;
+
+               foreach(item, orsubclause->args)
+               {
+                       if (match_clause_to_indexkey(rel, index, indexkey, opclass,
+                                                                                lfirst(item), false))
+                               quals = lappend(quals, lfirst(item));
+               }
+               if (quals == NIL)
+                       elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
+       }
+       else
+       {
+               /* we assume the caller passed a valid indexable qual */
+               quals = lcons(orsubclause, NIL);
+       }
+
+       return expand_indexqual_conditions(quals);
+}
+
 
 /****************************************************************************
  *                             ----  ROUTINES TO CHECK RESTRICTIONS  ----
@@ -614,8 +648,8 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
  *
  * Returns true if the clause can be used with this index key.
  *
- * NOTE:  returns false if clause is an OR or AND clause; to the extent
- * we cope with those at all, it is done by higher-level routines.
+ * NOTE:  returns false if clause is an OR or AND clause; it is the
+ * responsibility of higher-level routines to cope with those.
  */
 static bool
 match_clause_to_indexkey(RelOptInfo *rel,
index 2cc1c24..9eb0484 100644 (file)
@@ -8,14 +8,12 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.35 2000/01/26 05:56:34 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.36 2000/02/05 18:26:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-#include "postgres.h"
-
-
 
+#include "postgres.h"
 
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
@@ -33,7 +31,8 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
                                                                          List **indexids,
                                                                          Cost *cost);
 static void best_or_subclause_index(Query *root, RelOptInfo *rel,
-                                                                       List *indexqual, List *indices,
+                                                                       Expr *subclause, List *indices,
+                                                                       List **retIndexQual,
                                                                        Oid *retIndexid,
                                                                        Cost *retCost);
 
@@ -43,7 +42,7 @@ static void best_or_subclause_index(Query *root, RelOptInfo *rel,
  *       Creates index paths for indices that match 'or' clauses.
  *       create_index_paths() must already have been called.
  *
- * 'rel' is the relation entry for which the paths are to be defined on
+ * 'rel' is the relation entry for which the paths are to be created
  * 'clauses' is the list of available restriction clause nodes
  *
  * Returns a list of index path nodes.
@@ -164,21 +163,16 @@ best_or_subclause_indices(Query *root,
        foreach(slist, subclauses)
        {
                Expr       *subclause = lfirst(slist);
-               List       *indexqual;
+               List       *best_indexqual;
                Oid                     best_indexid;
                Cost            best_cost;
 
-               /* Convert this 'or' subclause to an indexqual list */
-               indexqual = make_ands_implicit(subclause);
-               /* expand special operators to indexquals the executor can handle */
-               indexqual = expand_indexqual_conditions(indexqual);
-
-               best_or_subclause_index(root, rel, indexqual, lfirst(indices),
-                                                               &best_indexid, &best_cost);
+               best_or_subclause_index(root, rel, subclause, lfirst(indices),
+                                                               &best_indexqual, &best_indexid, &best_cost);
 
                Assert(best_indexid != InvalidOid);
 
-               *indexquals = lappend(*indexquals, indexqual);
+               *indexquals = lappend(*indexquals, best_indexqual);
                *indexids = lappendi(*indexids, best_indexid);
                *cost += best_cost;
 
@@ -193,41 +187,49 @@ best_or_subclause_indices(Query *root,
  *       the least expensive.
  *
  * 'rel' is the node of the relation on which the index is defined
- * 'indexqual' is the indexqual list derived from the subclause
+ * 'subclause' is the OR subclause being considered
  * 'indices' is a list of IndexOptInfo nodes that match the subclause
+ * '*retIndexQual' gets a list of the indexqual conditions for the best index
  * '*retIndexid' gets the OID of the best index
  * '*retCost' gets the cost of a scan with that index
  */
 static void
 best_or_subclause_index(Query *root,
                                                RelOptInfo *rel,
-                                               List *indexqual,
+                                               Expr *subclause,
                                                List *indices,
+                                               List **retIndexQual,    /* return value */
                                                Oid *retIndexid,                /* return value */
                                                Cost *retCost)                  /* return value */
 {
-       bool            first_run = true;
+       bool            first_time = true;
        List       *ilist;
 
        /* if we don't match anything, return zeros */
+       *retIndexQual = NIL;
        *retIndexid = InvalidOid;
        *retCost = 0.0;
 
        foreach(ilist, indices)
        {
                IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
+               List       *indexqual;
                Cost            subcost;
 
                Assert(IsA(index, IndexOptInfo));
 
+               /* Convert this 'or' subclause to an indexqual list */
+               indexqual = extract_or_indexqual_conditions(rel, index, subclause);
+
                subcost = cost_index(root, rel, index, indexqual,
                                                         false);
 
-               if (first_run || subcost < *retCost)
+               if (first_time || subcost < *retCost)
                {
+                       *retIndexQual = indexqual;
                        *retIndexid = index->indexoid;
                        *retCost = subcost;
-                       first_run = false;
+                       first_time = false;
                }
        }
 }
index 3ba443f..c422654 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: paths.h,v 1.39 2000/01/26 05:58:20 momjian Exp $
+ * $Id: paths.h,v 1.40 2000/02/05 18:26:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,9 +38,19 @@ extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
                                   List *joininfo_list);
 extern Oid indexable_operator(Expr *clause, Oid opclass, Oid relam,
                                                          bool indexkey_on_left);
+extern List *extract_or_indexqual_conditions(RelOptInfo *rel,
+                                                                                        IndexOptInfo *index,
+                                                                                        Expr *orsubclause);
 extern List *expand_indexqual_conditions(List *indexquals);
 
 /*
+ * orindxpath.c
+ *       additional routines for indexable OR clauses
+ */
+extern List *create_or_index_paths(Query *root, RelOptInfo *rel,
+                                                                  List *clauses);
+
+/*
  * tidpath.h
  *       routines to generate tid paths
  */
@@ -52,12 +62,6 @@ extern List *create_tidscan_paths(Query *root, RelOptInfo *rel);
  */
 extern void update_rels_pathlist_for_joins(Query *root, List *joinrels);
 
-
-/*
- * orindxpath.c
- */
-extern List *create_or_index_paths(Query *root, RelOptInfo *rel, List *clauses);
-
 /*
  * pathkeys.c
  *       utilities for matching and building path keys
@@ -100,7 +104,7 @@ extern bool nonoverlap_sets(List *s1, List *s2);
 extern bool is_subset(List *s1, List *s2);
 
 /*
- * prototypes for path/prune.c
+ * prune.c
  */
 extern void merge_rels_with_same_relids(List *rel_list);
 extern void rels_set_cheapest(Query *root, List *rel_list);