99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.217 2007/03/17 00:11:04 tgl Exp $
12+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.218 2007/03/21 22:18:12 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
@@ -57,8 +57,8 @@ static Path *choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
5757static int bitmap_path_comparator (const void * a , const void * b );
5858static Cost bitmap_and_cost_est (PlannerInfo * root , RelOptInfo * rel ,
5959 List * paths , RelOptInfo * outer_rel );
60- static List * pull_indexpath_quals (Path * bitmapqual );
61- static bool lists_intersect_ptr (List * list1 , List * list2 );
60+ static void find_indexpath_quals (Path * bitmapqual , List * * quals , List * * preds );
61+ static bool lists_intersect (List * list1 , List * list2 );
6262static bool match_clause_to_indexcol (IndexOptInfo * index ,
6363 int indexcol , Oid opfamily ,
6464 RestrictInfo * rinfo ,
@@ -562,6 +562,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
562562 Path * * patharray ;
563563 Cost costsofar ;
564564 List * qualsofar ;
565+ List * firstpred ;
565566 ListCell * lastcell ;
566567 int i ;
567568 ListCell * l ;
@@ -586,8 +587,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
586587 * consider an index redundant if any of its index conditions were already
587588 * used by earlier indexes. (We could use predicate_implied_by to have a
588589 * more intelligent, but much more expensive, check --- but in most cases
589- * simple pointer equality should suffice, since after all the index
590- * conditions are all coming from the same RestrictInfo lists.)
590+ * simple equality should suffice.)
591591 *
592592 * You might think the condition for redundancy should be "all index
593593 * conditions already used", not "any", but this turns out to be wrong.
@@ -597,10 +597,27 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
597597 * non-selective. In any case, we'd surely be drastically misestimating
598598 * the selectivity if we count the same condition twice.
599599 *
600- * We include index predicate conditions in the redundancy test. Because
601- * the test is just for pointer equality and not equal(), the effect is
602- * that use of the same partial index in two different AND elements is
603- * considered redundant. (XXX is this too strong?)
600+ * We must also consider index predicate conditions in checking for
601+ * redundancy, because the estimated selectivity of a partial index
602+ * includes its predicate even if the explicit index conditions don't.
603+ * Here we have to work harder than just checking expression equality:
604+ * we check to see if any of the predicate clauses are implied by
605+ * index conditions or predicate clauses of previous paths. This covers
606+ * cases such as a condition "x = 42" used with a plain index, followed
607+ * by a clauseless scan of a partial index "WHERE x >= 40 AND x < 50".
608+ * Also, we reject indexes that have a qual condition matching any
609+ * previously-used index's predicate (by including predicate conditions
610+ * into qualsofar). It should be sufficient to check equality in this
611+ * case, not implication, since we've sorted the paths by selectivity
612+ * and so tighter conditions are seen first --- only for exactly equal
613+ * cases might the partial index come first.
614+ *
615+ * XXX the reason we need all these redundancy checks is that costsize.c
616+ * and clausesel.c aren't very smart about redundant clauses: they will
617+ * usually double-count the redundant clauses, producing a too-small
618+ * selectivity that makes a redundant AND look like it reduces the total
619+ * cost. Perhaps someday that code will be smarter and we can remove
620+ * these heuristics.
604621 *
605622 * Note: outputting the selected sub-paths in selectivity order is a good
606623 * thing even if we weren't using that as part of the selection method,
@@ -619,26 +636,46 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
619636
620637 paths = list_make1 (patharray [0 ]);
621638 costsofar = bitmap_and_cost_est (root , rel , paths , outer_rel );
622- qualsofar = pull_indexpath_quals (patharray [0 ]);
639+ find_indexpath_quals (patharray [0 ], & qualsofar , & firstpred );
640+ qualsofar = list_concat (qualsofar , firstpred );
623641 lastcell = list_head (paths ); /* for quick deletions */
624642
625643 for (i = 1 ; i < npaths ; i ++ )
626644 {
627645 Path * newpath = patharray [i ];
628646 List * newqual ;
647+ List * newpred ;
629648 Cost newcost ;
630649
631- newqual = pull_indexpath_quals (newpath );
632- if (lists_intersect_ptr (newqual , qualsofar ))
650+ find_indexpath_quals (newpath , & newqual , & newpred );
651+ if (lists_intersect (newqual , qualsofar ))
633652 continue ; /* consider it redundant */
653+ if (newpred )
654+ {
655+ bool redundant = false;
656+
657+ /* we check each predicate clause separately */
658+ foreach (l , newpred )
659+ {
660+ Node * np = (Node * ) lfirst (l );
661+
662+ if (predicate_implied_by (list_make1 (np ), qualsofar ))
663+ {
664+ redundant = true;
665+ break ; /* out of inner loop */
666+ }
667+ }
668+ if (redundant )
669+ continue ;
670+ }
634671 /* tentatively add newpath to paths, so we can estimate cost */
635672 paths = lappend (paths , newpath );
636673 newcost = bitmap_and_cost_est (root , rel , paths , outer_rel );
637674 if (newcost < costsofar )
638675 {
639676 /* keep newpath in paths, update subsidiary variables */
640677 costsofar = newcost ;
641- qualsofar = list_concat (qualsofar , newqual );
678+ qualsofar = list_concat (list_concat ( qualsofar , newqual ), newpred );
642679 lastcell = lnext (lastcell );
643680 }
644681 else
@@ -710,35 +747,39 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
710747}
711748
712749/*
713- * pull_indexpath_quals
750+ * find_indexpath_quals
714751 *
715- * Given the Path structure for a plain or bitmap indexscan, extract a list
752+ * Given the Path structure for a plain or bitmap indexscan, extract lists
716753 * of all the indexquals and index predicate conditions used in the Path.
717754 *
718755 * This is sort of a simplified version of make_restrictinfo_from_bitmapqual;
719756 * here, we are not trying to produce an accurate representation of the AND/OR
720757 * semantics of the Path, but just find out all the base conditions used.
721758 *
722- * The result list contains pointers to the expressions used in the Path,
759+ * The result lists contain pointers to the expressions used in the Path,
723760 * but all the list cells are freshly built, so it's safe to destructively
724- * modify the list (eg, by concat'ing it with other lists).
761+ * modify the lists (eg, by concat'ing with other lists).
725762 */
726- static List *
727- pull_indexpath_quals (Path * bitmapqual )
763+ static void
764+ find_indexpath_quals (Path * bitmapqual , List * * quals , List * * preds )
728765{
729- List * result = NIL ;
730766 ListCell * l ;
731767
768+ * quals = NIL ;
769+ * preds = NIL ;
770+
732771 if (IsA (bitmapqual , BitmapAndPath ))
733772 {
734773 BitmapAndPath * apath = (BitmapAndPath * ) bitmapqual ;
735774
736775 foreach (l , apath -> bitmapquals )
737776 {
738- List * sublist ;
777+ List * subquals ;
778+ List * subpreds ;
739779
740- sublist = pull_indexpath_quals ((Path * ) lfirst (l ));
741- result = list_concat (result , sublist );
780+ find_indexpath_quals ((Path * ) lfirst (l ), & subquals , & subpreds );
781+ * quals = list_concat (* quals , subquals );
782+ * preds = list_concat (* preds , subpreds );
742783 }
743784 }
744785 else if (IsA (bitmapqual , BitmapOrPath ))
@@ -747,36 +788,36 @@ pull_indexpath_quals(Path *bitmapqual)
747788
748789 foreach (l , opath -> bitmapquals )
749790 {
750- List * sublist ;
791+ List * subquals ;
792+ List * subpreds ;
751793
752- sublist = pull_indexpath_quals ((Path * ) lfirst (l ));
753- result = list_concat (result , sublist );
794+ find_indexpath_quals ((Path * ) lfirst (l ), & subquals , & subpreds );
795+ * quals = list_concat (* quals , subquals );
796+ * preds = list_concat (* preds , subpreds );
754797 }
755798 }
756799 else if (IsA (bitmapqual , IndexPath ))
757800 {
758801 IndexPath * ipath = (IndexPath * ) bitmapqual ;
759802
760- result = get_actual_clauses (ipath -> indexclauses );
761- result = list_concat ( result , list_copy (ipath -> indexinfo -> indpred ) );
803+ * quals = get_actual_clauses (ipath -> indexclauses );
804+ * preds = list_copy (ipath -> indexinfo -> indpred );
762805 }
763806 else
764807 elog (ERROR , "unrecognized node type: %d" , nodeTag (bitmapqual ));
765-
766- return result ;
767808}
768809
769810
770811/*
771- * lists_intersect_ptr
812+ * lists_intersect
772813 * Detect whether two lists have a nonempty intersection,
773- * using pointer equality to compare members.
814+ * using equal() to compare members.
774815 *
775816 * This possibly should go into list.c, but it doesn't yet have any use
776817 * except in choose_bitmap_and.
777818 */
778819static bool
779- lists_intersect_ptr (List * list1 , List * list2 )
820+ lists_intersect (List * list1 , List * list2 )
780821{
781822 ListCell * cell1 ;
782823
@@ -787,7 +828,7 @@ lists_intersect_ptr(List *list1, List *list2)
787828
788829 foreach (cell2 , list2 )
789830 {
790- if (lfirst (cell2 ) == datum1 )
831+ if (equal ( lfirst (cell2 ), datum1 ) )
791832 return true;
792833 }
793834 }
0 commit comments