// static void Explain::generatePlannerInfo(CanonicalQuery* query, PlanStageStats* winnerStats, const vector<PlanStageStats*>& rejectedStats, BSONObjBuilder* out) { BSONObjBuilder plannerBob(out->subobjStart("queryPlanner"));; plannerBob.append("plannerVersion", QueryPlanner::kPlannerVersion); // In general we should have a canonical query, but sometimes we may avoid // creating a canonical query as an optimization (specifically, the update system // does not canonicalize for idhack updates). In these cases, 'query' is NULL. if (NULL != query) { BSONObjBuilder parsedQueryBob(plannerBob.subobjStart("parsedQuery")); query->root()->toBSON(&parsedQueryBob); parsedQueryBob.doneFast(); } BSONObjBuilder winningPlanBob(plannerBob.subobjStart("winningPlan")); explainStatsTree(*winnerStats, Explain::QUERY_PLANNER, &winningPlanBob); winningPlanBob.doneFast(); // Genenerate array of rejected plans. BSONArrayBuilder allPlansBob(plannerBob.subarrayStart("rejectedPlans")); for (size_t i = 0; i < rejectedStats.size(); i++) { BSONObjBuilder childBob(allPlansBob.subobjStart()); explainStatsTree(*rejectedStats[i], Explain::QUERY_PLANNER, &childBob); } allPlansBob.doneFast(); plannerBob.doneFast(); }
// static void Explain::generatePlannerInfo(CanonicalQuery* query, PlanStageStats* winnerStats, const vector<PlanStageStats*>& rejectedStats, BSONObjBuilder* out) { BSONObjBuilder plannerBob(out->subobjStart("queryPlanner"));; plannerBob.append("plannerVersion", QueryPlanner::kPlannerVersion); BSONObjBuilder parsedQueryBob(plannerBob.subobjStart("parsedQuery")); query->root()->toBSON(&parsedQueryBob); parsedQueryBob.doneFast(); BSONObjBuilder winningPlanBob(plannerBob.subobjStart("winningPlan")); explainStatsTree(*winnerStats, Explain::QUERY_PLANNER, &winningPlanBob); winningPlanBob.doneFast(); // Genenerate array of rejected plans. BSONArrayBuilder allPlansBob(plannerBob.subarrayStart("rejectedPlans")); for (size_t i = 0; i < rejectedStats.size(); i++) { BSONObjBuilder childBob(allPlansBob.subobjStart()); explainStatsTree(*rejectedStats[i], Explain::QUERY_PLANNER, &childBob); } allPlansBob.doneFast(); plannerBob.doneFast(); }
// static void Explain::generateExecStats(PlanStageStats* stats, BSONObjBuilder* out) { out->appendNumber("nReturned", stats->common.advanced); out->appendNumber("executionTimeMillis", stats->common.executionTimeMillis); // Flatten the stats tree into a list. vector<PlanStageStats*> statsNodes; flattenStatsTree(stats, &statsNodes); // Iterate over all stages in the tree and get the total number of keys/docs examined. // These are just aggregations of information already available in the stats tree. size_t totalKeysExamined = 0; size_t totalDocsExamined = 0; for (size_t i = 0; i < statsNodes.size(); ++i) { totalKeysExamined += getKeysExamined(statsNodes[i]->stageType, statsNodes[i]->specific.get()); totalDocsExamined += getDocsExamined(statsNodes[i]->stageType, statsNodes[i]->specific.get()); } out->appendNumber("totalKeysExamined", totalKeysExamined); out->appendNumber("totalDocsExamined", totalDocsExamined); // Add the tree of stages, with individual execution stats for each stage. BSONObjBuilder stagesBob(out->subobjStart("executionStages")); explainStatsTree(*stats, Explain::EXEC_STATS, &stagesBob); stagesBob.doneFast(); }