diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index 5ecacf746e..ef6b11c6da 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -1414,17 +1414,37 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions) for (auto inversion : inversions) { - const auto indexScratch = inversion->scratch; - - // If the explicit plan doesn't mention this index, fake it as used - // thus excluding it from the cost-based algorithm. Otherwise, - // given this index is suitable for navigation, also mark it as used. - - if ((indexScratch && - (indexScratch->index->idx_runtime_flags & idx_plan_dont_use)) || - (!customPlan && inversion == navigationCandidate)) + if (const auto indexScratch = inversion->scratch) { - inversion->used = true; + const auto idx = indexScratch->index; + + // If the explicit plan doesn't mention this index, fake it as used + // thus excluding it from the cost-based algorithm. Otherwise, + // given this index is suitable for navigation, also mark it as used. + + if (((idx->idx_runtime_flags & idx_plan_dont_use)) || + (!customPlan && inversion == navigationCandidate)) + { + inversion->used = true; + } + + // If the index is conditional and its condition is also present in + // some other inversion as a boolean (it represents the OR operation), + // fake these other inversions as used, so that the full index scan would + // be preferred to multiple range scans. The cost-based algorithm below + // cannot handle it currently. + + if (idx->idx_flags & idx_condition) + { + for (auto otherInversion : inversions) + { + if (otherInversion->boolean && + idx->idx_condition->sameAs(otherInversion->boolean, true)) + { + otherInversion->used = true; + } + } + } } } @@ -1460,11 +1480,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions) if (!invCandidate) invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool()); - if (!currentInv->inversion && currentInv->scratch) - invCandidate->inversion = makeIndexScanNode(currentInv->scratch); - else - invCandidate->inversion = currentInv->inversion; - + const auto inversionNode = (!currentInv->inversion && currentInv->scratch) ? + makeIndexScanNode(currentInv->scratch) : currentInv->inversion; + invCandidate->inversion = inversionNode; invCandidate->dbkeyRanges.assign(currentInv->dbkeyRanges); invCandidate->unique = currentInv->unique; invCandidate->selectivity = currentInv->selectivity; @@ -1653,12 +1671,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions) if (!invCandidate) { invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool()); - if (!bestCandidate->inversion && bestCandidate->scratch) { - invCandidate->inversion = makeIndexScanNode(bestCandidate->scratch); - } - else { - invCandidate->inversion = bestCandidate->inversion; - } + const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ? + makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion; + invCandidate->inversion = inversionNode; invCandidate->dbkeyRanges.assign(bestCandidate->dbkeyRanges); invCandidate->unique = bestCandidate->unique; invCandidate->selectivity = bestCandidate->selectivity; @@ -1685,17 +1700,10 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions) } else if (!bestCandidate->condition) { - if (!bestCandidate->inversion && bestCandidate->scratch) - { - invCandidate->inversion = composeInversion(invCandidate->inversion, - makeIndexScanNode(bestCandidate->scratch), InversionNode::TYPE_AND); - } - else - { - invCandidate->inversion = composeInversion(invCandidate->inversion, - bestCandidate->inversion, InversionNode::TYPE_AND); - } - + const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ? + makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion; + invCandidate->inversion = composeInversion(invCandidate->inversion, + inversionNode, InversionNode::TYPE_AND); invCandidate->dbkeyRanges.join(bestCandidate->dbkeyRanges); invCandidate->unique = (invCandidate->unique || bestCandidate->unique); invCandidate->selectivity = totalSelectivity; @@ -1770,6 +1778,16 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch, if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE) return false; + const auto idx = indexScratch->index; + + if (idx->idx_flags & idx_condition) + { + // If index condition matches the boolean, this should not be + // considered a match. Full index scan will be used instead. + if (idx->idx_condition->sameAs(boolean, true)) + return false; + } + const auto cmpNode = nodeAs(boolean); const auto missingNode = nodeAs(boolean); const auto listNode = nodeAs(boolean); @@ -1804,16 +1822,6 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch, ValueExprNode* value2 = (cmpNode && cmpNode->blrOp == blr_between) ? cmpNode->arg3 : nullptr; - const auto idx = indexScratch->index; - - if (idx->idx_flags & idx_condition) - { - // If index condition matches the boolean, this should not be - // considered a match. Full index scan will be used instead. - if (idx->idx_condition->sameAs(boolean, true)) - return false; - } - if (idx->idx_flags & idx_expression) { // see if one side or the other is matchable to the index expression