Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SERVER-78113: not cache meaningless plan, it will increased memory overhead and increase computing overhead. #1555

Open
wants to merge 1 commit into
base: v5.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/mongo/db/exec/plan_cache_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,15 @@ void logNotCachingNoData(std::string&& solution) {
"Not caching query because this solution has no cache data",
"solutions"_attr = redact(solution));
}

void logNotCachingOneWorkesAndZeroResults(std::string&& query, double score, std::string winnerPlanSummary) {
LOGV2_DEBUG(20570,
1,
"Winning plan had zero results, and only one work, skip caching",
"query"_attr = redact(query),
"winnerScore"_attr = score,
"winnerPlanSummary"_attr = winnerPlanSummary);

}
} // namespace log_detail
} // namespace mongo::plan_cache_util
39 changes: 39 additions & 0 deletions src/mongo/db/exec/plan_cache_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void logTieForBest(std::string&& query,
std::string runnerUpPlanSummary);
void logNotCachingZeroResults(std::string&& query, double score, std::string winnerPlanSummary);
void logNotCachingNoData(std::string&& solution);
void logNotCachingOneWorkesAndZeroResults(std::string&& query, double score, std::string winnerPlanSummary);
} // namespace log_detail

/**
Expand Down Expand Up @@ -154,6 +155,44 @@ void updatePlanCache(
}
}

// when the mode is PlanCachingMode::AlwaysCache or PlanCachingMode::SometimesCache, there is a special case.
// take Classic plan cache for example:
// If the winning index's advanced = 0 && works == 1 && isEOF == true, which means we didn't get any data to rank score, all candidates
// score is same. the score of the calculation is meaningless.
//
//In this case, if we cache the plan, it will increased memory overhead. when the cached plan stage pick best plan,
//it will trigger replan. this will increase computing overhead.
if (canCache == true) {
std::unique_ptr<PlanExplainer> winnerExplainer;
if constexpr (std::is_same_v<PlanStageType, std::unique_ptr<sbe::PlanStage>>) {
winnerExplainer = plan_explainer_factory::make(candidates[winnerIdx].root.get(),
&candidates[winnerIdx].data,
candidates[winnerIdx].solution.get());
auto const& rankingStats = ranking->getStats<sbe::PlanStageStats>();
auto numReads = calculateNumberOfReads(rankingStats.candidatePlanStats[winnerIdx].get());

if (numReads == 1 && rankingStats.candidatePlanStats[winnerIdx]->common.advances == 0
&& rankingStats.candidatePlanStats[winnerIdx]->common.isEOF == true) {
canCache = false;
log_detail::logNotCachingOneWorkesAndZeroResults(
query.toStringShort(), ranking->scores[0], winnerExplainer->getPlanSummary());
}
} else {
static_assert(std::is_same_v<PlanStageType, PlanStage*>);
winnerExplainer = plan_explainer_factory::make(candidates[winnerIdx].root);

std::unique_ptr<PlanStageStats> bestCandidateStatTrees;
bestCandidateStatTrees = candidates[winnerIdx].root->getStats();
if (bestCandidateStatTrees->common.advanced == 0
&& bestCandidateStatTrees->common.works== 1
&& bestCandidateStatTrees->common.isEOF == true) {
canCache = false;
log_detail::logNotCachingOneWorkesAndZeroResults(
query.toStringShort(), ranking->scores[0], winnerExplainer->getPlanSummary());
}
}
}

// Store the choice we just made in the cache, if the query is of a type that is safe to
// cache.
if (PlanCache::shouldCacheQuery(query) && canCache) {
Expand Down