8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 22:43:03 +01:00

Fixed #7804: The partial index is not involved when filtering conditions through OR

This commit is contained in:
Dmitry Yemanov 2023-10-24 10:07:41 +03:00
parent a6d322f1b2
commit 09ae711a4e
2 changed files with 58 additions and 33 deletions

View File

@ -356,6 +356,16 @@ public:
static double getSelectivity(const BoolExprNode* node)
{
if (const auto listNode = nodeAs<InListBoolNode>(node))
{
const auto selectivity = REDUCE_SELECTIVITY_FACTOR_EQUALITY *
listNode->list->items.getCount();
return MIN(selectivity, MAXIMUM_SELECTIVITY);
}
if (nodeIs<MissingBoolNode>(node))
return REDUCE_SELECTIVITY_FACTOR_EQUALITY;
if (const auto cmpNode = nodeAs<ComparativeBoolNode>(node))
{
switch (cmpNode->blrOp)
@ -382,16 +392,6 @@ public:
break;
}
}
else if (const auto listNode = nodeAs<InListBoolNode>(node))
{
const auto selectivity = REDUCE_SELECTIVITY_FACTOR_EQUALITY *
listNode->list->items.getCount();
return MIN(selectivity, MAXIMUM_SELECTIVITY);
}
else if (nodeIs<MissingBoolNode>(node))
{
return REDUCE_SELECTIVITY_FACTOR_EQUALITY;
}
return REDUCE_SELECTIVITY_FACTOR_OTHER;
}

View File

@ -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<BinaryBoolNode>(boolean);
if (binaryNode && binaryNode->blrOp == blr_or)
{
if (matchSubset(binaryNode->arg1, sub) ||
matchSubset(binaryNode->arg2, sub))
{
return true;
}
binaryNode = nodeAs<BinaryBoolNode>(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<BinaryBoolNode>(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<NotBoolNode>(boolean);
const auto missingNode = notNode ? nodeAs<MissingBoolNode>(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;