diff options
author | Ted Tuckman <ted.tuckman@mongodb.com> | 2020-10-13 13:11:41 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-12-01 17:07:38 +0000 |
commit | a9982732333fdc6fb853aa8d8596a85cd008f125 (patch) | |
tree | 67752d957d5408f6baebf98fa097a3830ebcbd22 /src/mongo/db/query/plan_executor_impl.cpp | |
parent | 9b15b5a07c8e47e9be4f886ce7c6076fd5c66e87 (diff) | |
download | mongo-a9982732333fdc6fb853aa8d8596a85cd008f125.tar.gz |
SERVER-48625 Add query knobs to explain output and logs
Diffstat (limited to 'src/mongo/db/query/plan_executor_impl.cpp')
-rw-r--r-- | src/mongo/db/query/plan_executor_impl.cpp | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/src/mongo/db/query/plan_executor_impl.cpp b/src/mongo/db/query/plan_executor_impl.cpp index 36dedccdd53..be1a2a34fca 100644 --- a/src/mongo/db/query/plan_executor_impl.cpp +++ b/src/mongo/db/query/plan_executor_impl.cpp @@ -132,9 +132,9 @@ PlanExecutorImpl::PlanExecutorImpl(OperationContext* opCtx, invariant(!_expCtx || _expCtx->opCtx == _opCtx); invariant(!_cq || !_expCtx || _cq->getExpCtx() == _expCtx); - // If this PlanExecutor is executing a COLLSCAN, keep a pointer directly to the COLLSCAN stage. - // This is used for change streams in order to keep the the latest oplog timestamp and post - // batch resume token up to date as the oplog scan progresses. + // If this PlanExecutor is executing a COLLSCAN, keep a pointer directly to the COLLSCAN + // stage. This is used for change streams in order to keep the the latest oplog timestamp + // and post batch resume token up to date as the oplog scan progresses. if (auto collectionScan = getStageByType(_root.get(), STAGE_COLLSCAN)) { _collScanStage = static_cast<CollectionScan*>(collectionScan); } @@ -152,6 +152,18 @@ PlanExecutorImpl::PlanExecutorImpl(OperationContext* opCtx, } uassertStatusOK(_pickBestPlan()); + + if (_qs) { + _planExplainer->updateEnumeratorExplainInfo(_qs->_enumeratorExplainInfo); + } else if (const MultiPlanStage* mps = getMultiPlanStage()) { + const QuerySolution* soln = mps->bestSolution(); + _planExplainer->updateEnumeratorExplainInfo(soln->_enumeratorExplainInfo); + + } else if (auto subplan = getStageByType(_root.get(), STAGE_SUBPLAN)) { + auto subplanStage = static_cast<SubplanStage*>(subplan); + _planExplainer->updateEnumeratorExplainInfo( + subplanStage->compositeSolution()->_enumeratorExplainInfo); + } } Status PlanExecutorImpl::_pickBestPlan() { @@ -180,8 +192,9 @@ Status PlanExecutorImpl::_pickBestPlan() { return cachedPlan->pickBestPlan(_yieldPolicy.get()); } - // Finally, we might have an explicit TrialPhase. This specifies exactly two candidate plans, - // one of which is to be evaluated. If it fails the trial, then the backup plan is adopted. + // Finally, we might have an explicit TrialPhase. This specifies exactly two candidate + // plans, one of which is to be evaluated. If it fails the trial, then the backup plan is + // adopted. foundStage = getStageByType(_root.get(), STAGE_TRIAL); if (foundStage) { TrialStage* trialStage = static_cast<TrialStage*>(foundStage); @@ -329,8 +342,8 @@ PlanExecutor::ExecState PlanExecutorImpl::_getNextImpl(Snapshotted<Document>* ob size_t writeConflictsInARow = 0; // Capped insert data; declared outside the loop so we hold a shared pointer to the capped - // insert notifier the entire time we are in the loop. Holding a shared pointer to the capped - // insert notifier is necessary for the notifierVersion to advance. + // insert notifier the entire time we are in the loop. Holding a shared pointer to the + // capped insert notifier is necessary for the notifierVersion to advance. insert_listener::CappedInsertNotifierData cappedInsertNotifierData; if (insert_listener::shouldListenForInserts(_opCtx, _cq.get())) { // We always construct the CappedInsertNotifier for awaitData cursors. @@ -502,8 +515,8 @@ UpdateResult PlanExecutorImpl::getUpdateResult() const { updateStats.objInserted); }; - // If we're updating a non-existent collection, then the delete plan may have an EOF as the root - // stage. + // If we're updating a non-existent collection, then the delete plan may have an EOF as the + // root stage. if (_root->stageType() == STAGE_EOF) { const auto stats = std::make_unique<UpdateStats>(); return updateStatsToResult(static_cast<const UpdateStats&>(*stats)); @@ -530,14 +543,14 @@ UpdateResult PlanExecutorImpl::getUpdateResult() const { long long PlanExecutorImpl::executeDelete() { _executePlan(); - // If we're deleting from a non-existent collection, then the delete plan may have an EOF as the - // root stage. + // If we're deleting from a non-existent collection, then the delete plan may have an EOF as + // the root stage. if (_root->stageType() == STAGE_EOF) { return 0LL; } - // If the collection exists, the delete plan may either have a delete stage at the root, or (for - // findAndModify) a projection stage wrapping a delete stage. + // If the collection exists, the delete plan may either have a delete stage at the root, or + // (for findAndModify) a projection stage wrapping a delete stage. switch (_root->stageType()) { case StageType::STAGE_PROJECTION_DEFAULT: case StageType::STAGE_PROJECTION_COVERED: |