mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:03:03 +01:00
Postfix for #7804: The partial index is not involved when filtering conditions through OR. Use the full index scan instead of multiple range scans ORed afterwards.
This commit is contained in:
parent
63e6ead37b
commit
90401f7210
@ -1414,17 +1414,37 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
|
|||||||
|
|
||||||
for (auto inversion : inversions)
|
for (auto inversion : inversions)
|
||||||
{
|
{
|
||||||
const auto indexScratch = inversion->scratch;
|
if (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))
|
|
||||||
{
|
{
|
||||||
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)
|
if (!invCandidate)
|
||||||
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
|
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
|
||||||
|
|
||||||
if (!currentInv->inversion && currentInv->scratch)
|
const auto inversionNode = (!currentInv->inversion && currentInv->scratch) ?
|
||||||
invCandidate->inversion = makeIndexScanNode(currentInv->scratch);
|
makeIndexScanNode(currentInv->scratch) : currentInv->inversion;
|
||||||
else
|
invCandidate->inversion = inversionNode;
|
||||||
invCandidate->inversion = currentInv->inversion;
|
|
||||||
|
|
||||||
invCandidate->dbkeyRanges.assign(currentInv->dbkeyRanges);
|
invCandidate->dbkeyRanges.assign(currentInv->dbkeyRanges);
|
||||||
invCandidate->unique = currentInv->unique;
|
invCandidate->unique = currentInv->unique;
|
||||||
invCandidate->selectivity = currentInv->selectivity;
|
invCandidate->selectivity = currentInv->selectivity;
|
||||||
@ -1653,12 +1671,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
|
|||||||
if (!invCandidate)
|
if (!invCandidate)
|
||||||
{
|
{
|
||||||
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
|
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
|
||||||
if (!bestCandidate->inversion && bestCandidate->scratch) {
|
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
|
||||||
invCandidate->inversion = makeIndexScanNode(bestCandidate->scratch);
|
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
|
||||||
}
|
invCandidate->inversion = inversionNode;
|
||||||
else {
|
|
||||||
invCandidate->inversion = bestCandidate->inversion;
|
|
||||||
}
|
|
||||||
invCandidate->dbkeyRanges.assign(bestCandidate->dbkeyRanges);
|
invCandidate->dbkeyRanges.assign(bestCandidate->dbkeyRanges);
|
||||||
invCandidate->unique = bestCandidate->unique;
|
invCandidate->unique = bestCandidate->unique;
|
||||||
invCandidate->selectivity = bestCandidate->selectivity;
|
invCandidate->selectivity = bestCandidate->selectivity;
|
||||||
@ -1685,17 +1700,10 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
|
|||||||
}
|
}
|
||||||
else if (!bestCandidate->condition)
|
else if (!bestCandidate->condition)
|
||||||
{
|
{
|
||||||
if (!bestCandidate->inversion && bestCandidate->scratch)
|
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
|
||||||
{
|
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
|
||||||
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
||||||
makeIndexScanNode(bestCandidate->scratch), InversionNode::TYPE_AND);
|
inversionNode, InversionNode::TYPE_AND);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
|
||||||
bestCandidate->inversion, InversionNode::TYPE_AND);
|
|
||||||
}
|
|
||||||
|
|
||||||
invCandidate->dbkeyRanges.join(bestCandidate->dbkeyRanges);
|
invCandidate->dbkeyRanges.join(bestCandidate->dbkeyRanges);
|
||||||
invCandidate->unique = (invCandidate->unique || bestCandidate->unique);
|
invCandidate->unique = (invCandidate->unique || bestCandidate->unique);
|
||||||
invCandidate->selectivity = totalSelectivity;
|
invCandidate->selectivity = totalSelectivity;
|
||||||
@ -1770,6 +1778,16 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
|
|||||||
if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE)
|
if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE)
|
||||||
return false;
|
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<ComparativeBoolNode>(boolean);
|
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
|
||||||
const auto missingNode = nodeAs<MissingBoolNode>(boolean);
|
const auto missingNode = nodeAs<MissingBoolNode>(boolean);
|
||||||
const auto listNode = nodeAs<InListBoolNode>(boolean);
|
const auto listNode = nodeAs<InListBoolNode>(boolean);
|
||||||
@ -1804,16 +1822,6 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
|
|||||||
ValueExprNode* value2 = (cmpNode && cmpNode->blrOp == blr_between) ?
|
ValueExprNode* value2 = (cmpNode && cmpNode->blrOp == blr_between) ?
|
||||||
cmpNode->arg3 : nullptr;
|
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)
|
if (idx->idx_flags & idx_expression)
|
||||||
{
|
{
|
||||||
// see if one side or the other is matchable to the index expression
|
// see if one side or the other is matchable to the index expression
|
||||||
|
Loading…
Reference in New Issue
Block a user