From c65e55c9e6b20cb8f216154173d71e4d8cd0543c Mon Sep 17 00:00:00 2001 From: dimitr Date: Thu, 11 Mar 2010 10:03:32 +0000 Subject: [PATCH] Fixed CORE-1550: Unnecessary index scan happens when the same index is mapped to both WHERE and ORDER BY clauses. --- src/jrd/Optimizer.cpp | 14 +++++++++++--- src/jrd/Optimizer.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/jrd/Optimizer.cpp b/src/jrd/Optimizer.cpp index 1506af01ab..3986a027ab 100644 --- a/src/jrd/Optimizer.cpp +++ b/src/jrd/Optimizer.cpp @@ -816,6 +816,7 @@ IndexScratch::IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* ix, selectivity = MAXIMUM_SELECTIVITY; candidate = false; scopeCandidate = false; + utilized = false; lowerCount = 0; upperCount = 0; nonFullMatchedSegments = 0; @@ -842,7 +843,8 @@ IndexScratch::IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* ix, // Compound indexes are generally less compressed. factor = 0.7; } - Database* dbb = tdbb->getDatabase(); + + const Database* const dbb = tdbb->getDatabase(); cardinality = (csb_tail->csb_cardinality * (2 + (length * factor))) / (dbb->dbb_page_size - BTR_SIZE); cardinality = MAX(cardinality, MINIMUM_CARDINALITY); } @@ -863,6 +865,7 @@ IndexScratch::IndexScratch(MemoryPool& p, const IndexScratch& scratch) : cardinality = scratch.cardinality; candidate = scratch.candidate; scopeCandidate = scratch.scopeCandidate; + utilized = scratch.utilized; lowerCount = scratch.lowerCount; upperCount = scratch.upperCount; nonFullMatchedSegments = scratch.nonFullMatchedSegments; @@ -1464,6 +1467,7 @@ IndexTableScan* OptimizerRetrieval::generateNavigation() *sort = NULL; idx->idx_runtime_flags |= idx_navigate; + indexScratches[i].utilized = true; jrd_nod* const index_node = makeIndexScanNode(&indexScratches[i]); const USHORT key_length = ROUNDUP(BTR_key_length(tdbb, relation, idx), sizeof(SLONG)); return FB_NEW(*tdbb->getDefaultPool()) @@ -1530,6 +1534,7 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio { IndexScratch& scratch = (*fromIndexScratches)[i]; scratch.scopeCandidate = false; + scratch.utilized = false; scratch.lowerCount = 0; scratch.upperCount = 0; scratch.nonFullMatchedSegments = MAX_INDEX_SEGMENTS + 1; @@ -1886,7 +1891,8 @@ jrd_nod* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) const // already at index scan. But this rule doesn't apply to nod_equiv // which requires NULLs to be found in the index. // A second exception is when this index is used for navigation. - if (ignoreNullsOnScan && !(idx->idx_runtime_flags & idx_navigate)) { + if (ignoreNullsOnScan && !(idx->idx_runtime_flags & idx_navigate)) + { retrieval->irb_generic |= irb_ignore_null_value_key; } @@ -1980,7 +1986,9 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in inversion[i]->used = false; if (inversion[i]->scratch) { - if (inversion[i]->scratch->idx->idx_runtime_flags & idx_plan_dont_use) { + if (inversion[i]->scratch->utilized || + inversion[i]->scratch->idx->idx_runtime_flags & idx_plan_dont_use) + { inversion[i]->used = true; } } diff --git a/src/jrd/Optimizer.h b/src/jrd/Optimizer.h index 22e9c89633..c1079a46fb 100644 --- a/src/jrd/Optimizer.h +++ b/src/jrd/Optimizer.h @@ -137,6 +137,7 @@ public: double selectivity; // calculated selectivity for this index bool candidate; // used when deciding which indices to use bool scopeCandidate; // used when making inversion based on scope + bool utilized; // index is already utilized by some scan int lowerCount; // int upperCount; // int nonFullMatchedSegments; //