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:
parent
6b22039d4f
commit
a5cde2bbb4
@ -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,9 +1367,8 @@ 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;
|
||||||
@ -1538,15 +1558,13 @@ 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
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user