OSDN Git Service

Fix best_inner_indexscan to actually enforce that an "inner indexscan" use
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 8 Apr 2006 21:32:17 +0000 (21:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 8 Apr 2006 21:32:17 +0000 (21:32 +0000)
at least one join condition as an indexqual.  Before bitmap indexscans, this
oversight didn't really cost much except for redundantly considering the
same join paths twice; but as of 8.1 it could result in silly bitmap scans
that would do the same BitmapOr twice and then BitmapAnd these together :-(

src/backend/optimizer/path/indxpath.c

index c740a89..1184a04 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.202 2006/03/05 15:58:28 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.203 2006/04/08 21:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -253,6 +253,10 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
        List       *all_clauses = NIL;          /* not computed till needed */
        ListCell   *ilist;
 
+       /* quick exit if no available clauses */
+       if (clauses == NIL)
+               return NIL;
+
        foreach(ilist, rel->indexlist)
        {
                IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
@@ -1370,16 +1374,20 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
        }
 
        /*
-        * Find all the relevant restriction and join clauses.
+        * Find all the relevant join clauses.
         */
        clause_list = find_clauses_for_join(root, rel, outer_relids, isouterjoin);
 
        /*
         * Find all the index paths that are usable for this join, except for
-        * stuff involving OR and ScalarArrayOpExpr clauses.
+        * stuff involving OR and ScalarArrayOpExpr clauses.  We can use both
+        * join and restriction clauses as indexquals, but we insist the path
+        * use at least one join clause (else it'd not be an "inner indexscan"
+        * but a plain indexscan, and those have already been considered).
         */
        indexpaths = find_usable_indexes(root, rel,
-                                                                        clause_list, NIL,
+                                                                        clause_list,
+                                                                        rel->baserestrictinfo,
                                                                         false, true,
                                                                         outer_relids,
                                                                         SAOP_FORBID);
@@ -1389,7 +1397,8 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
         * clauses present in the clause list.
         */
        bitindexpaths = generate_bitmap_or_paths(root, rel,
-                                                                                        clause_list, NIL,
+                                                                                        clause_list,
+                                                                                        rel->baserestrictinfo,
                                                                                         true,
                                                                                         outer_relids);
 
@@ -1439,13 +1448,12 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
 
 /*
  * find_clauses_for_join
- *       Generate a list of clauses that are potentially useful for
+ *       Generate a list of join clauses that are potentially useful for
  *       scanning rel as the inner side of a nestloop join.
  *
- * We consider both join and restriction clauses.  Any joinclause that uses
- * only otherrels in the specified outer_relids is fair game.  But there must
- * be at least one such joinclause in the final list, otherwise we return NIL
- * indicating that there isn't any potential win here.
+ * Any joinclause that uses only otherrels in the specified outer_relids is
+ * fair game.  Note that restriction clauses on rel can also be used in
+ * forming index conditions, but we do not include those here.
  */
 static List *
 find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
@@ -1473,28 +1481,28 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
 
        bms_free(join_relids);
 
-       /* if no join clause was matched then forget it, per comments above */
+       /* quick exit if no join clause was matched */
        if (clause_list == NIL)
                return NIL;
 
        /*
-        * We can also use any plain restriction clauses for the rel.  We put
-        * these at the front of the clause list for the convenience of
-        * remove_redundant_join_clauses, which can never remove non-join clauses
-        * and hence won't be able to get rid of a non-join clause if it appears
-        * after a join clause it is redundant with.
-        */
-       clause_list = list_concat(list_copy(rel->baserestrictinfo), clause_list);
-
-       /*
         * We may now have clauses that are known redundant.  Get rid of 'em.
         */
        if (list_length(clause_list) > 1)
-       {
                clause_list = remove_redundant_join_clauses(root,
                                                                                                        clause_list,
                                                                                                        isouterjoin);
-       }
+
+       /*
+        * We might have found join clauses that are known redundant with
+        * restriction clauses on rel (due to conclusions drawn by implied
+        * equality deduction; without that, this would obviously never happen).
+        * Get rid of them too.
+        */
+       if (rel->baserestrictinfo != NIL)
+               clause_list = select_nonredundant_join_clauses(root, clause_list,
+                                                                                                          rel->baserestrictinfo,
+                                                                                                          isouterjoin);
 
        return clause_list;
 }