@@ -827,6 +827,8 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
827
827
unsigned scope) const
828
828
{
829
829
const double cardinality = csb->csb_rpt [stream].csb_cardinality ;
830
+ fb_assert (cardinality);
831
+ const double minSelectivity = MIN (MAXIMUM_SELECTIVITY / cardinality, DEFAULT_SELECTIVITY);
830
832
831
833
// Walk through indexes to calculate selectivity / candidate
832
834
MatchedBooleanList matches;
@@ -885,6 +887,15 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
885
887
}
886
888
}
887
889
890
+ auto selectivity = idx->idx_rpt [j].idx_selectivity ;
891
+ const auto useDefaultSelectivity = (selectivity <= 0 );
892
+
893
+ // When the index selectivity is zero then the statement is prepared
894
+ // on an empty table or the statistics aren't updated. So assume every
895
+ // match to represent 1/10 of the maximum selectivity.
896
+ if (useDefaultSelectivity)
897
+ selectivity = MAX (scratch.selectivity * DEFAULT_SELECTIVITY, minSelectivity);
898
+
888
899
if (segment.scanType == segmentScanList)
889
900
{
890
901
if (listCount) // we cannot have more than one list matched to an index
@@ -907,10 +918,10 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
907
918
// This is a perfect usable segment thus update root selectivity
908
919
scratch.lowerCount ++;
909
920
scratch.upperCount ++;
910
- scratch.selectivity = idx->idx_rpt [j].idx_selectivity ;
911
921
scratch.nonFullMatchedSegments = idx->idx_count - (j + 1 );
912
922
// Add matches for this segment to the main matches list
913
923
matches.join (segment.matches );
924
+ scratch.selectivity = selectivity;
914
925
915
926
// An equality scan for any unique index cannot retrieve more
916
927
// than one row. The same is true for an equivalence scan for
@@ -931,6 +942,12 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
931
942
// so we can stop looking further, because this is the best
932
943
// one we can get.
933
944
unique = true ;
945
+
946
+ // If selectivity is assumed, a better guess for the unique match
947
+ // would be 1 / cardinality
948
+ if (useDefaultSelectivity)
949
+ scratch.selectivity = minSelectivity;
950
+
934
951
break ;
935
952
}
936
953
@@ -942,58 +959,53 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
942
959
}
943
960
else
944
961
{
945
- // This is our last segment that we can use,
946
- // estimate the selectivity
947
- auto selectivity = scratch.selectivity ;
948
- double factor = 1 ;
949
-
950
- switch (segment.scanType )
962
+ if (segment.scanType != segmentScanNone)
951
963
{
952
- case segmentScanBetween:
953
- scratch.lowerCount ++;
954
- scratch.upperCount ++;
955
- selectivity = idx->idx_rpt [j].idx_selectivity ;
956
- factor = REDUCE_SELECTIVITY_FACTOR_BETWEEN;
957
- break ;
958
-
959
- case segmentScanLess:
960
- scratch.upperCount ++;
961
- selectivity = idx->idx_rpt [j].idx_selectivity ;
962
- factor = REDUCE_SELECTIVITY_FACTOR_LESS;
963
- break ;
964
-
965
- case segmentScanGreater:
966
- scratch.lowerCount ++;
967
- selectivity = idx->idx_rpt [j].idx_selectivity ;
968
- factor = REDUCE_SELECTIVITY_FACTOR_GREATER;
969
- break ;
970
-
971
- case segmentScanStarting:
972
- case segmentScanEqual:
973
- case segmentScanEquivalent:
974
- scratch.lowerCount ++;
975
- scratch.upperCount ++;
976
- selectivity = idx->idx_rpt [j].idx_selectivity ;
977
- factor = REDUCE_SELECTIVITY_FACTOR_STARTING;
978
- break ;
964
+ // This is our last segment that we can use,
965
+ // estimate the selectivity
966
+ double factor = 1 ;
979
967
980
- default :
981
- fb_assert (segment.scanType == segmentScanNone);
982
- break ;
983
- }
968
+ switch (segment.scanType )
969
+ {
970
+ case segmentScanBetween:
971
+ scratch.lowerCount ++;
972
+ scratch.upperCount ++;
973
+ factor = REDUCE_SELECTIVITY_FACTOR_BETWEEN;
974
+ break ;
975
+
976
+ case segmentScanLess:
977
+ scratch.upperCount ++;
978
+ factor = REDUCE_SELECTIVITY_FACTOR_LESS;
979
+ break ;
980
+
981
+ case segmentScanGreater:
982
+ scratch.lowerCount ++;
983
+ factor = REDUCE_SELECTIVITY_FACTOR_GREATER;
984
+ break ;
985
+
986
+ case segmentScanStarting:
987
+ case segmentScanEqual:
988
+ case segmentScanEquivalent:
989
+ scratch.lowerCount ++;
990
+ scratch.upperCount ++;
991
+ factor = REDUCE_SELECTIVITY_FACTOR_STARTING;
992
+ break ;
993
+
994
+ default :
995
+ fb_assert (false );
996
+ break ;
997
+ }
984
998
985
- // Adjust the compound selectivity using the reduce factor.
986
- // It should be better than the previous segment but worse
987
- // than a full match.
988
- const double diffSelectivity = scratch.selectivity - selectivity;
989
- selectivity += (diffSelectivity * factor);
990
- fb_assert (selectivity <= scratch.selectivity );
991
- scratch.selectivity = selectivity;
999
+ // Adjust the compound selectivity using the reduce factor.
1000
+ // It should be better than the previous segment but worse
1001
+ // than a full match.
1002
+ const double diffSelectivity = scratch.selectivity - selectivity;
1003
+ selectivity += (diffSelectivity * factor);
1004
+ fb_assert (selectivity <= scratch.selectivity );
1005
+ scratch.selectivity = selectivity;
992
1006
993
- if (segment.scanType != segmentScanNone)
994
- {
995
- matches.join (segment.matches );
996
1007
scratch.nonFullMatchedSegments = idx->idx_count - j;
1008
+ matches.join (segment.matches );
997
1009
}
998
1010
999
1011
break ;
@@ -1003,19 +1015,7 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions,
1003
1015
if (scratch.scopeCandidate )
1004
1016
{
1005
1017
double selectivity = scratch.selectivity ;
1006
-
1007
- // When the index selectivity is zero then the statement is prepared
1008
- // on an empty table or the statistics aren't updated. The priorly
1009
- // calculated selectivity is meaningless in this case. So instead:
1010
- // - for an unique match, estimate the selectivity via the stream cardinality;
1011
- // - for a non-unique one, assume 1/10 of the maximum selectivity, so that
1012
- // at least some indexes could be utilized by the optimizer.
1013
- if (idx->idx_selectivity <= 0 )
1014
- {
1015
- selectivity = unique ?
1016
- MIN (MAXIMUM_SELECTIVITY / cardinality, DEFAULT_SELECTIVITY) :
1017
- DEFAULT_SELECTIVITY;
1018
- }
1018
+ fb_assert (selectivity);
1019
1019
1020
1020
// Calculate the cost (only index pages) for this index
1021
1021
auto cost = DEFAULT_INDEX_COST + selectivity * scratch.cardinality ;
0 commit comments