diff --git a/src/jrd/optimizer/Optimizer.h b/src/jrd/optimizer/Optimizer.h index ffd050c5ed..6ee2b75e70 100644 --- a/src/jrd/optimizer/Optimizer.h +++ b/src/jrd/optimizer/Optimizer.h @@ -356,6 +356,16 @@ public: static double getSelectivity(const BoolExprNode* node) { + if (const auto listNode = nodeAs(node)) + { + const auto selectivity = REDUCE_SELECTIVITY_FACTOR_EQUALITY * + listNode->list->items.getCount(); + return MIN(selectivity, MAXIMUM_SELECTIVITY); + } + + if (nodeIs(node)) + return REDUCE_SELECTIVITY_FACTOR_EQUALITY; + if (const auto cmpNode = nodeAs(node)) { switch (cmpNode->blrOp) @@ -382,16 +392,6 @@ public: break; } } - else if (const auto listNode = nodeAs(node)) - { - const auto selectivity = REDUCE_SELECTIVITY_FACTOR_EQUALITY * - listNode->list->items.getCount(); - return MIN(selectivity, MAXIMUM_SELECTIVITY); - } - else if (nodeIs(node)) - { - return REDUCE_SELECTIVITY_FACTOR_EQUALITY; - } return REDUCE_SELECTIVITY_FACTOR_OTHER; } diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index 09e8d8d9cd..fe55636541 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -104,6 +104,34 @@ namespace return newValue; } + bool matchSubset(const BoolExprNode* boolean, const BoolExprNode* sub) + { + if (boolean->sameAs(sub, true)) + return true; + + auto binaryNode = nodeAs(boolean); + if (binaryNode && binaryNode->blrOp == blr_or) + { + if (matchSubset(binaryNode->arg1, sub) || + matchSubset(binaryNode->arg2, sub)) + { + return true; + } + + binaryNode = nodeAs(sub); + if (binaryNode && binaryNode->blrOp == blr_or) + { + if (matchSubset(boolean, binaryNode->arg1) && + matchSubset(boolean, binaryNode->arg2)) + { + return true; + } + } + } + + return false; + }; + } // namespace @@ -723,24 +751,22 @@ bool Retrieval::checkIndexCondition(index_desc& idx, MatchedBooleanList& matches const auto boolean = idxIter.object(); // If the index condition is (A OR B) and any of the {A, B} is present - // among the available booleans, then the index is possibly usable - const auto binaryNode = nodeAs(boolean); - if (binaryNode && binaryNode->blrOp == blr_or) + // among the available booleans, then the index is possibly usable. + // Note: this check also includes the exact match. + + for (iter.rewind(); iter.hasData(); ++iter) { - for (iter.rewind(); iter.hasData(); ++iter) + if (matchSubset(boolean, *iter)) { - if (binaryNode->arg1->sameAs(*iter, true) || - binaryNode->arg2->sameAs(*iter, true)) - { - matches.add(*iter); - break; - } + matches.add(*iter); + break; } } // If the index condition is (A IS NOT NULL) and the available booleans // includes any comparative predicate that explicitly mentions A, // then the index is possibly usable + const auto notNode = nodeAs(boolean); const auto missingNode = notNode ? nodeAs(notNode->arg) : nullptr; if (missingNode) @@ -767,17 +793,6 @@ bool Retrieval::checkIndexCondition(index_desc& idx, MatchedBooleanList& matches } } - // If conjunct of the index condition matches any available boolean, - // then the index is possibly usable - for (iter.rewind(); iter.hasData(); ++iter) - { - if (idxIter.object()->sameAs(*iter, true)) - { - matches.add(*iter); - break; - } - } - idx.idx_fraction *= optimizer->getSelectivity(boolean); } @@ -833,7 +848,7 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions, if (scratch.candidate) { matches.assign(scratch.matches); - scratch.selectivity = idx->idx_fraction; + scratch.selectivity = MAXIMUM_SELECTIVITY; bool unique = false; unsigned listCount = 0; @@ -1027,7 +1042,7 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions, const auto invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool()); invCandidate->unique = unique; - invCandidate->selectivity = selectivity; + invCandidate->selectivity = idx->idx_fraction * selectivity; invCandidate->cost = cost; invCandidate->nonFullMatchedSegments = scratch.nonFullMatchedSegments; invCandidate->matchedSegments = MAX(scratch.lowerCount, scratch.upperCount); @@ -1054,6 +1069,13 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions, invCandidate->scratch = &scratch; invCandidate->matches.assign(scratch.matches); + for (auto match : invCandidate->matches) + { + match->findDependentFromStreams(csb, stream, + &invCandidate->dependentFromStreams); + } + + invCandidate->dependencies = invCandidate->dependentFromStreams.getCount(); inversions.add(invCandidate); } } @@ -1377,6 +1399,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions) } } + if (currentInv->boolean && matches.exist(currentInv->boolean)) + anyMatchAlreadyUsed = true; + if (anyMatchAlreadyUsed && !customPlan) { currentInv->used = true;