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 ,
5959List * 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 ,
6363int indexcol ,Oid opfamily ,
6464RestrictInfo * rinfo ,
@@ -562,6 +562,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
562562Path * * patharray ;
563563Cost costsofar ;
564564List * qualsofar ;
565+ List * firstpred ;
565566ListCell * lastcell ;
566567int i ;
567568ListCell * 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
620637paths = list_make1 (patharray [0 ]);
621638costsofar = 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 );
623641lastcell = list_head (paths );/* for quick deletions */
624642
625643for (i = 1 ;i < npaths ;i ++ )
626644{
627645Path * newpath = patharray [i ];
628646List * newqual ;
647+ List * newpred ;
629648Cost 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 ))
633652continue ;/* 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 */
635672paths = lappend (paths ,newpath );
636673newcost = bitmap_and_cost_est (root ,rel ,paths ,outer_rel );
637674if (newcost < costsofar )
638675{
639676/* keep newpath in paths, update subsidiary variables */
640677costsofar = newcost ;
641- qualsofar = list_concat (qualsofar ,newqual );
678+ qualsofar = list_concat (list_concat ( qualsofar ,newqual ), newpred );
642679lastcell = lnext (lastcell );
643680}
644681else
@@ -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, extracta list
752+ * Given the Path structure for a plain or bitmap indexscan, extractlists
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 resultlist contains pointers to the expressions used in the Path,
759+ * The resultlists 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 thelist (eg, by concat'ing it with other lists).
761+ * modify thelists (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 ;
730766ListCell * l ;
731767
768+ * quals = NIL ;
769+ * preds = NIL ;
770+
732771if (IsA (bitmapqual ,BitmapAndPath ))
733772{
734773BitmapAndPath * apath = (BitmapAndPath * )bitmapqual ;
735774
736775foreach (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}
744785else if (IsA (bitmapqual ,BitmapOrPath ))
@@ -747,36 +788,36 @@ pull_indexpath_quals(Path *bitmapqual)
747788
748789foreach (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}
756799else if (IsA (bitmapqual ,IndexPath ))
757800{
758801IndexPath * 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}
763806else
764807elog (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- *usingpointer equality to compare members.
814+ *usingequal() 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{
781822ListCell * cell1 ;
782823
@@ -787,7 +828,7 @@ lists_intersect_ptr(List *list1, List *list2)
787828
788829foreach (cell2 ,list2 )
789830{
790- if (lfirst (cell2 )== datum1 )
831+ if (equal ( lfirst (cell2 ), datum1 ) )
791832return true;
792833}
793834}