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

Correction for CORE-1550: Unnecessary index scan happens when the same index is mapped to both WHERE and ORDER BY clauses.

Also resolved CORE-1846: Allow index walk (ORDER plan) when there's a composite index {A, B} and the query looks like WHERE A = ? ORDER BY B.
This commit is contained in:
dimitr 2013-11-28 17:26:54 +00:00
parent 6b22039d4f
commit a5cde2bbb4

View File

@ -674,6 +674,7 @@ void OptimizerRetrieval::analyzeNavigation()
{ {
IndexScratch* const indexScratch = &indexScratches[i]; IndexScratch* const indexScratch = &indexScratches[i];
const index_desc* const idx = indexScratch->idx; const index_desc* const idx = indexScratch->idx;
const int equalSegments = MIN(indexScratch->lowerCount, indexScratch->upperCount);
// if the number of fields in the sort is greater than the number of // if the number of fields in the sort is greater than the number of
// fields in the index, the index will not be used to optimize the // fields in the index, the index will not be used to optimize the
@ -704,6 +705,7 @@ void OptimizerRetrieval::analyzeNavigation()
bool usableIndex = true; bool usableIndex = true;
const index_desc::idx_repeat* idx_tail = idx->idx_rpt; const index_desc::idx_repeat* idx_tail = idx->idx_rpt;
const index_desc::idx_repeat* const idx_end = idx_tail + idx->idx_count;
NestConst<ValueExprNode>* ptr = sort->expressions.begin(); NestConst<ValueExprNode>* ptr = sort->expressions.begin();
const bool* descending = sort->descending.begin(); const bool* descending = sort->descending.begin();
const int* nullOrder = sort->nullOrder.begin(); const int* nullOrder = sort->nullOrder.begin();
@ -723,13 +725,27 @@ void OptimizerRetrieval::analyzeNavigation()
break; break;
} }
} }
else if (!(fieldNode = node->as<FieldNode>()) || else if (!(fieldNode = node->as<FieldNode>()) || fieldNode->fieldStream != stream)
fieldNode->fieldStream != stream ||
fieldNode->fieldId != idx_tail->idx_field)
{ {
usableIndex = false; usableIndex = false;
break; break;
} }
else
{
for (; idx_tail < idx_end && fieldNode->fieldId != idx_tail->idx_field; idx_tail++)
{
const int segmentNumber = idx_tail - idx->idx_rpt;
if (segmentNumber >= equalSegments)
break;
}
if (idx_tail >= idx_end || fieldNode->fieldId != idx_tail->idx_field)
{
usableIndex = false;
break;
}
}
if ((*descending && !(idx->idx_flags & idx_descending)) || if ((*descending && !(idx->idx_flags & idx_descending)) ||
(!*descending && (idx->idx_flags & idx_descending)) || (!*descending && (idx->idx_flags & idx_descending)) ||
@ -1273,7 +1289,12 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
for (i = 0; i < navigationCandidate->segments.getCount(); i++) for (i = 0; i < navigationCandidate->segments.getCount(); i++)
{ {
const IndexScratchSegment* const segment = navigationCandidate->segments[i]; const IndexScratchSegment* const segment = navigationCandidate->segments[i];
matches.join(segment->matches);
for (size_t j = 0; j < segment->matches.getCount(); j++)
{
if (!matches.exist(segment->matches[j]))
matches.add(segment->matches[j]);
}
} }
} }
@ -1346,10 +1367,9 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
// index, add also the other matches from this index. // index, add also the other matches from this index.
for (size_t j = 0; j < currentInv->matches.getCount(); j++) for (size_t j = 0; j < currentInv->matches.getCount(); j++)
{ {
if (!matches.exist(currentInv->matches[j])) { if (!matches.exist(currentInv->matches[j]))
matches.add(currentInv->matches[j]); matches.add(currentInv->matches[j]);
} }
}
// Restart loop, because other indexes could also be excluded now. // Restart loop, because other indexes could also be excluded now.
restartLoop = true; restartLoop = true;
break; break;
@ -1538,17 +1558,15 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
for (size_t j = 0; j < bestCandidate->matches.getCount(); j++) for (size_t j = 0; j < bestCandidate->matches.getCount(); j++)
{ {
if (!matches.exist(bestCandidate->matches[j])) { if (!matches.exist(bestCandidate->matches[j]))
matches.add(bestCandidate->matches[j]); matches.add(bestCandidate->matches[j]);
} }
}
if (bestCandidate->boolean) if (bestCandidate->boolean)
{ {
if (!matches.exist(bestCandidate->boolean)) { if (!matches.exist(bestCandidate->boolean))
matches.add(bestCandidate->boolean); matches.add(bestCandidate->boolean);
} }
} }
}
else else
{ {
fb_assert(!bestCandidate->condition); fb_assert(!bestCandidate->condition);
@ -1604,9 +1622,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
} }
} }
if (invCandidate && matches.getCount()) { if (invCandidate && matches.getCount())
invCandidate->matches.join(matches); invCandidate->matches.join(matches);
}
return invCandidate; return invCandidate;
} }