PlanExecutor:
總的來說是一個根據內部的執行樹(Execution Tree)從數據庫中獲取數據的一個上層抽象結構/接口,在Query Engine執行find()
時就用這貨獲取數據,它還用於與查詢優化器(Query Optimizer)或Cache等交互。
主要對外接口: 一系列的make()用於構建PlanExecutor. 服務於其本身的工廠設計模式,
- static StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> make(…) 構建一個PlanExecutor一般情況下需要CanonicalQuery(CQ),但不是必須的,比如Aggregate query可能創建個PlanExecutor用於獲取數據,但不提供CQ
ExecState getNext(Document* objOut, RecordId* dlOut)
: 用於從數據庫獲取數據 ...
主要內部成員:
- WorkingSet: 是MongoDB用來存放於內存的數據工作集,例如當
PlanExecutor
在一步一步執行getNext()
過去數據的時候,獲取的數據都是存入WorkingSet的。getNext()返回執行結果的同時返回給caller的RecordId* dlOut
正是用於從WorkingSet中獲取數據的ID. - QuerySolution: 所用的Query Solution
- PlanStage: Query Solution對應的真正用於執行獲取數據的數據結構。 ...
getExecutor() 主要流程:
Return value:
struct PrepareExecutionResult {
...
unique_ptr<CanonicalQuery> canonicalQuery; // 可能會被修改
// 查詢樹. 內部是一個查詢樹(節點爲QuerySolutionNode),代表一個Query Plan, 可用於生成PlanStage tree.
unique_ptr<QuerySolution> querySolution;
// 對應Query Plan的 Query Execution Plan(QEP), 真正用於獲取數據的底層數據結構。
unique_ptr<PlanStage> root;
};
主要流程: prepareExecution() -> PlanExecutor::make()
prepareExecution(): 爲特定Query(canonicalQuery)構建一個執行樹(Execution Tree).
1) 準備QueryPlannerParams(Query Planner需要的參數), 比如選擇可用的indexes(過濾掉不可用的index,比如當用戶設置了index filters
的時候,或者被用戶隱藏的index(V4.4開始,用戶可以隱藏index, 見SERVER-26589))
2) 準備IdHack Plan(當Query Planner決定使用_id
索引的時候)
3) 查Cache是否有Cached Plan可以用
4) QueryPlanner::plan()(產出備選query solutions/plans), 如果備選query solutions大於一個的話,則會有一個MultiPlanStage
作爲最後Query Plan的root stage,該stage之後排序,選擇最佳Query Solution用於該Query獲取數據.(Link Token: [TODO],哪天有空再補個Mongo如何選擇最佳query plan的筆記吧...)
5) Misc. 其他優化...
PlanExecutor::make()
: 構建PlanExecutor
...