9
9
*
10
10
*
11
11
* 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 $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
@@ -57,8 +57,8 @@ static Path *choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
57
57
static int bitmap_path_comparator (const void * a , const void * b );
58
58
static Cost bitmap_and_cost_est (PlannerInfo * root , RelOptInfo * rel ,
59
59
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 );
62
62
static bool match_clause_to_indexcol (IndexOptInfo * index ,
63
63
int indexcol , Oid opfamily ,
64
64
RestrictInfo * rinfo ,
@@ -562,6 +562,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
562
562
Path * * patharray ;
563
563
Cost costsofar ;
564
564
List * qualsofar ;
565
+ List * firstpred ;
565
566
ListCell * lastcell ;
566
567
int i ;
567
568
ListCell * l ;
@@ -586,8 +587,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
586
587
* consider an index redundant if any of its index conditions were already
587
588
* used by earlier indexes. (We could use predicate_implied_by to have a
588
589
* 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.)
591
591
*
592
592
* You might think the condition for redundancy should be "all index
593
593
* conditions already used", not "any", but this turns out to be wrong.
@@ -597,10 +597,27 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
597
597
* non-selective. In any case, we'd surely be drastically misestimating
598
598
* the selectivity if we count the same condition twice.
599
599
*
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.
604
621
*
605
622
* Note: outputting the selected sub-paths in selectivity order is a good
606
623
* 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,
619
636
620
637
paths = list_make1 (patharray [0 ]);
621
638
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 );
623
641
lastcell = list_head (paths ); /* for quick deletions */
624
642
625
643
for (i = 1 ; i < npaths ; i ++ )
626
644
{
627
645
Path * newpath = patharray [i ];
628
646
List * newqual ;
647
+ List * newpred ;
629
648
Cost newcost ;
630
649
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 ))
633
652
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
+ }
634
671
/* tentatively add newpath to paths, so we can estimate cost */
635
672
paths = lappend (paths , newpath );
636
673
newcost = bitmap_and_cost_est (root , rel , paths , outer_rel );
637
674
if (newcost < costsofar )
638
675
{
639
676
/* keep newpath in paths, update subsidiary variables */
640
677
costsofar = newcost ;
641
- qualsofar = list_concat (qualsofar , newqual );
678
+ qualsofar = list_concat (list_concat ( qualsofar , newqual ), newpred );
642
679
lastcell = lnext (lastcell );
643
680
}
644
681
else
@@ -710,35 +747,39 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
710
747
}
711
748
712
749
/*
713
- * pull_indexpath_quals
750
+ * find_indexpath_quals
714
751
*
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
716
753
* of all the indexquals and index predicate conditions used in the Path.
717
754
*
718
755
* This is sort of a simplified version of make_restrictinfo_from_bitmapqual;
719
756
* here, we are not trying to produce an accurate representation of the AND/OR
720
757
* semantics of the Path, but just find out all the base conditions used.
721
758
*
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,
723
760
* 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).
725
762
*/
726
- static List *
727
- pull_indexpath_quals (Path * bitmapqual )
763
+ static void
764
+ find_indexpath_quals (Path * bitmapqual , List * * quals , List * * preds )
728
765
{
729
- List * result = NIL ;
730
766
ListCell * l ;
731
767
768
+ * quals = NIL ;
769
+ * preds = NIL ;
770
+
732
771
if (IsA (bitmapqual , BitmapAndPath ))
733
772
{
734
773
BitmapAndPath * apath = (BitmapAndPath * ) bitmapqual ;
735
774
736
775
foreach (l , apath -> bitmapquals )
737
776
{
738
- List * sublist ;
777
+ List * subquals ;
778
+ List * subpreds ;
739
779
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 );
742
783
}
743
784
}
744
785
else if (IsA (bitmapqual , BitmapOrPath ))
@@ -747,36 +788,36 @@ pull_indexpath_quals(Path *bitmapqual)
747
788
748
789
foreach (l , opath -> bitmapquals )
749
790
{
750
- List * sublist ;
791
+ List * subquals ;
792
+ List * subpreds ;
751
793
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 );
754
797
}
755
798
}
756
799
else if (IsA (bitmapqual , IndexPath ))
757
800
{
758
801
IndexPath * ipath = (IndexPath * ) bitmapqual ;
759
802
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 );
762
805
}
763
806
else
764
807
elog (ERROR , "unrecognized node type: %d" , nodeTag (bitmapqual ));
765
-
766
- return result ;
767
808
}
768
809
769
810
770
811
/*
771
- * lists_intersect_ptr
812
+ * lists_intersect
772
813
* Detect whether two lists have a nonempty intersection,
773
- * using pointer equality to compare members.
814
+ * using equal() to compare members.
774
815
*
775
816
* This possibly should go into list.c, but it doesn't yet have any use
776
817
* except in choose_bitmap_and.
777
818
*/
778
819
static bool
779
- lists_intersect_ptr (List * list1 , List * list2 )
820
+ lists_intersect (List * list1 , List * list2 )
780
821
{
781
822
ListCell * cell1 ;
782
823
@@ -787,7 +828,7 @@ lists_intersect_ptr(List *list1, List *list2)
787
828
788
829
foreach (cell2 , list2 )
789
830
{
790
- if (lfirst (cell2 ) == datum1 )
831
+ if (equal ( lfirst (cell2 ), datum1 ) )
791
832
return true;
792
833
}
793
834
}
0 commit comments