diff options
author | samontea <merciers.merciers@gmail.com> | 2019-05-31 14:05:37 -0400 |
---|---|---|
committer | samontea <merciers.merciers@gmail.com> | 2019-07-10 16:07:42 -0400 |
commit | 6bba6446e632b557ccc03834d4d48e90336679fc (patch) | |
tree | 8f550393c99b15f4b27d9bbb27115fc451930be7 /src/mongo/db/query/plan_ranker.cpp | |
parent | 0434f018920206c197ab06b96e1a74dcbdf8885a (diff) | |
download | mongo-6bba6446e632b557ccc03834d4d48e90336679fc.tar.gz |
SERVER-41279 Eliminate failed plans from consideration during query planning
Diffstat (limited to 'src/mongo/db/query/plan_ranker.cpp')
-rw-r--r-- | src/mongo/db/query/plan_ranker.cpp | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/src/mongo/db/query/plan_ranker.cpp b/src/mongo/db/query/plan_ranker.cpp index ff2e636a28a..2970428be3b 100644 --- a/src/mongo/db/query/plan_ranker.cpp +++ b/src/mongo/db/query/plan_ranker.cpp @@ -65,10 +65,9 @@ using std::endl; using std::vector; // static -size_t PlanRanker::pickBestPlan(const vector<CandidatePlan>& candidates, PlanRankingDecision* why) { +StatusWith<std::unique_ptr<PlanRankingDecision>> PlanRanker::pickBestPlan( + const vector<CandidatePlan>& candidates) { invariant(!candidates.empty()); - invariant(why); - // A plan that hits EOF is automatically scored above // its peers. If multiple plans hit EOF during the same // set of round-robin calls to work(), then all such plans @@ -89,28 +88,44 @@ size_t PlanRanker::pickBestPlan(const vector<CandidatePlan>& candidates, PlanRan // Holds (score, candidateInndex). // Used to derive scores and candidate ordering. vector<std::pair<double, size_t>> scoresAndCandidateindices; + vector<size_t> failed; // Compute score for each tree. Record the best. for (size_t i = 0; i < statTrees.size(); ++i) { - LOG(5) << "Scoring plan " << i << ":" << endl - << redact(candidates[i].solution->toString()) << "Stats:\n" - << redact(Explain::statsToBSON(*statTrees[i]).jsonString(Strict, true)); - LOG(2) << "Scoring query plan: " << Explain::getPlanSummary(candidates[i].root) - << " planHitEOF=" << statTrees[i]->common.isEOF; - - double score = scoreTree(statTrees[i].get()); - LOG(5) << "score = " << score; - if (statTrees[i]->common.isEOF) { - LOG(5) << "Adding +" << eofBonus << " EOF bonus to score."; - score += 1; + if (!candidates[i].failed) { + LOG(5) << "Scoring plan " << i << ":" << endl + << redact(candidates[i].solution->toString()) << "Stats:\n" + << redact(Explain::statsToBSON(*statTrees[i]).jsonString(Strict, true)); + LOG(2) << "Scoring query plan: " << Explain::getPlanSummary(candidates[i].root) + << " planHitEOF=" << statTrees[i]->common.isEOF; + + double score = scoreTree(statTrees[i].get()); + LOG(5) << "score = " << score; + if (statTrees[i]->common.isEOF) { + LOG(5) << "Adding +" << eofBonus << " EOF bonus to score."; + score += 1; + } + + scoresAndCandidateindices.push_back(std::make_pair(score, i)); + } else { + failed.push_back(i); + LOG(2) << "Not scording plan: " << Explain::getPlanSummary(candidates[i].root) + << " because the plan failed."; } - scoresAndCandidateindices.push_back(std::make_pair(score, i)); + } + + // If there isn't a viable plan we should error. + if (scoresAndCandidateindices.size() == 0U) { + return {ErrorCodes::Error(31157), + "No viable plan was found because all candidate plans failed."}; } // Sort (scores, candidateIndex). Get best child and populate candidate ordering. std::stable_sort( scoresAndCandidateindices.begin(), scoresAndCandidateindices.end(), scoreComparator); + auto why = std::make_unique<PlanRankingDecision>(); + // Determine whether plans tied for the win. if (scoresAndCandidateindices.size() > 1U) { double bestScore = scoresAndCandidateindices[0].first; @@ -124,6 +139,7 @@ size_t PlanRanker::pickBestPlan(const vector<CandidatePlan>& candidates, PlanRan why->stats.clear(); why->scores.clear(); why->candidateOrder.clear(); + why->failedCandidates = std::move(failed); for (size_t i = 0; i < scoresAndCandidateindices.size(); ++i) { double score = scoresAndCandidateindices[i].first; size_t candidateIndex = scoresAndCandidateindices[i].second; @@ -155,9 +171,11 @@ size_t PlanRanker::pickBestPlan(const vector<CandidatePlan>& candidates, PlanRan why->scores.push_back(score); why->candidateOrder.push_back(candidateIndex); } + for (auto& i : why->failedCandidates) { + why->stats.push_back(std::move(statTrees[i])); + } - size_t bestChild = scoresAndCandidateindices[0].second; - return bestChild; + return StatusWith<std::unique_ptr<PlanRankingDecision>>(std::move(why)); } // TODO: Move this out. This is a signal for ranking but will become its own complicated |