执行计划PlanExecutor

本文介绍MongoDB中PlanExecutor的工作原理,包括如何选择最优查询方案并执行。通过MultiPlanStage示例展示PlanRanker如何评估不同方案,以提高查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PlanExecutor的主要作用是选出最佳的QuerySolution, 并且执行该solution。
整个PlanExecutor 对象的结构如下图:

这里写图片描述

1. 生成PlanExecutor对象

 这里采用了工厂模式, PlanExecutor::make产生指定的PlanExecutor对象;

2. 选择最佳计划

从上图可见,这里分成4中情况:
SubplanStage, 主要是针对$or 的处理, CachedPlanStage是从Cache里得到的solution的处理阶段, 
MultiPlanStage以及普通的stage, 相关的代码都放在: src/mongo/db/exec 目录, 
根据stage的类型可以找到相关的代码。
Status PlanExecutor::pickBestPlan(YieldPolicy policy) {
    ...

    // First check if we need to do subplanning.
    PlanStage* foundStage = getStageByType(_root.get(), STAGE_SUBPLAN);
    if (foundStage) {
        SubplanStage* subplan = static_cast<SubplanStage*>(foundStage);
        return subplan->pickBestPlan(_yieldPolicy.get());
    }

    // If we didn't have to do subplanning, we might still have to do regular
    // multi plan selection...
    foundStage = getStageByType(_root.get(), STAGE_MULTI_PLAN);
    if (foundStage) {
        MultiPlanStage* mps = static_cast<MultiPlanStage*>(foundStage);
        return mps->pickBestPlan(_yieldPolicy.get());
    }

    foundStage = getStageByType(_root.get(), STAGE_CACHED_PLAN);
    if (foundStage) {
        CachedPlanStage* cachedPlan = static_cast<CachedPlanStage*>(foundStage);
        return cachedPlan->pickBestPlan(_yieldPolicy.get());
    }

    // Either we chose a plan, or no plan selection was required. In both cases,
    // our work has been successfully completed.
    return Status::OK();
}
我们以MultiPlanStage为例, 通过MultiPlanStage::pickBestPlan的得到最佳的Plan, 
PlanRanker::pickBestPlan会为每一个plan打分, 并且找到分数最高的一个。

Status MultiPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) {
    ...
        // 得到Candidate stage
        bool moreToDo = workAllPlans(numResults, yieldPolicy);
    ...


    std::unique_ptr<PlanRankingDecision> ranking(new PlanRankingDecision);
    _bestPlanIdx = PlanRanker::pickBestPlan(_candidates, ranking.get());

    CandidatePlan& bestCandidate = _candidates[_bestPlanIdx];
    std::list<WorkingSetID>& alreadyProduced = bestCandidate.results;
    const auto& bestSolution = bestCandidate.solution;

3. 执行计划的详情查询

每一个stage都会记录一些统计的数据, 包含CommonStats, 和该中类型特定的stats, 例如, FetchStats,记录这些, 主要是为了在explain命令或者stats 命令中使用。例如, 我们可以看到某一次查询的一些详细信息: parsedQuery, winningPlan,executionStats 以及他们的详细信息, 透过这些信息, 我们可以知道当前的查询操作, 我们是否使用索引, 或者使用了那个索引; 我们还可以知道我们最终得到的plan的执行的统计信息, 例如, 执行的时间, 查询的文档, 索引等。

"queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.test",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "key1" : {
                "$eq" : "value1"
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "key1" : 1
                },
                "indexName" : "key1_1",
                "isMultiKey" : false,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "forward",
                "indexBounds" : {
                    "key1" : [
                        "[\"value1\", \"value1\"]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 1,
        "totalDocsExamined" : 1,
        "executionStages" : {
            "stage" : "FETCH",
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 0,
            "works" : 2,
            "advanced" : 1,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 1,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 1,
                "executionTimeMillisEstimate" : 0,
                "works" : 2,
                "advanced" : 1,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "key1" : 1
                },
                "indexName" : "key1_1",
                "isMultiKey" : false,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "forward",
                "indexBounds" : {
                    "key1" : [
                        "[\"value1\", \"value1\"]"
                    ]
                },
                "keysExamined" : 1,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值