MongoDB干货系列2-MongoDB执行计划分析详解(2)
来源:互联网 发布:ubuntu 软件包破损 编辑:程序博客网 时间:2024/06/05 16:24
MongoDB干货系列2-MongoDB执行计划分析详解(2)
MongoDB干货系列2-MongoDB执行计划分析详解(2)
八月 4, 2015E叔的博客、博客eshujiushiwo
写在之前的话
作为近年最为火热的文档型数据库,MongoDB受到了越来越多人的关注,但是由于国内的MongoDB相关技术分享屈指可数,不少朋友向我抱怨无从下手。
《MongoDB干货系列》将从实际应用的角度来进行MongoDB的一些列干货的分享,将覆盖调优,troubleshooting等方面,希望能对大家带来帮助。
如果希望了解更多MongoDB基础的信息,还请大家Google下。
要保证数据库处于高效、稳定的状态,除了良好的硬件基础、高效高可用的数据库架构、贴合业务的数据模型之外,高效的查询语句也是不可少的。那么,如何查看并判断我们的执行计划呢?我们今天就来谈论下MongoDB的执行计划分析。
引子
MongoDB 3.0之后,explain的返回与使用方法与之前版本有了不少变化,介于3.0之后的优秀特色,本文仅针对MongoDB 3.0+的explain进行讨论。
现版本explain有三种模式,分别如下:
§ queryPlanner
§ executionStats
§ allPlansExecution
由于文章字数原因,本系列将分为三个部分。
第一部分
第二部分
第三部分
本文是第二部分,主要是对IndexFilter与Stage进行分析。
正文
IndexFilter
IndexFilter决定了查询优化器对于某一类型的查询将如何使用index,indexFilter仅影响查询优化器对于该类查询可以用尝试哪些index的执行计划分析,查询优化器还是根据分析情况选择最优计划。
如果某一类型的查询设定了IndexFilter,那么执行时通过hint指定了其他的index,查询优化器将会忽略hint所设置index,仍然使用indexfilter中设定的查询计划。
IndexFilter可以通过命令移除,也将在实例重启后清空。
IndexFilter的创建
可以通过如下命令为某一个collection建立indexFilter
db.runCommand( { planCacheSetFilter: <collection>, query: <query>, sort: <sort>, projection: <projection>, indexes: [ <index1>, <index2>, ...] })
db.runCommand( { planCacheSetFilter: "orders", query: { status: "A" }, indexes: [ { cust_id: 1, status: 1 }, { status: 1, order_date: -1 } ] })
上图针对orders表建立了一个indexFilter,indexFilter指定了对于orders表只有status条件(仅对status进行查询,无sort等)的查询的indexes,故下图的查询语句的查询优化器仅仅会从{cust_id:1,status:1}
和{status:1,order_date:-1}
中进行winning plan的选择
db.orders.find( { status: "D" } )db.orders.find( { status: "P" } )
indexFilter的列表
可以通过如下命令展示某一个collecton的所有indexFilter
db.runCommand( { planCacheListFilters: <collection> } )
indexFilter的删除
可以通过如下命令对IndexFilter进行删除
db.runCommand( { planCacheClearFilters: <collection>, query: <query pattern>, sort: <sort specification>, projection: <projection specification> })
Stage的意义
如explain.queryPlanner.winningPlan.stage和explain.queryPlanner.winningPlan.inputStage等。
文档中仅有如下几类介绍
COLLSCAN
全表扫描
IXSCAN
索引扫描
FETCH
根据索引去检索指定document
SHARD_MERGE
将各个分片返回数据进行merge
但是根据源码中的信息,个人还总结了文档中没有的如下几类(常用如下,由于是通过源码查找,可能有所遗漏)
SORT
表明在内存中进行了排序(与老版本的scanAndOrder:true一致)
LIMIT
使用limit限制返回数
SKIP
使用skip进行跳过
IDHACK
针对_id进行查询
SHARDING_FILTER
通过mongos对分片数据进行查询
COUNT
利用db.coll.explain().count()之类进行count运算
COUNTSCAN
count不使用用Index进行count时的stage返回
COUNT_SCAN
count使用了Index进行count时的stage返回
SUBPLA
未使用到索引的$or查询的stage返回
TEXT
使用全文索引进行查询时候的stage返回
PROJECTION
限定返回字段时候stage的返回
部分源码如下:
mongo/jstests/libs/analyze_plan.js
/** * A query is covered iff it does *not* have a FETCH stage or a COLLSCAN. * * Given the root stage of explain's BSON representation of a query plan ('root'), * returns true if the plan is index only. Otherwise returns false. */function isIndexOnly(root) { return !planHasStage(root, "FETCH") && !planHasStage(root, "COLLSCAN");}/** * Returns true if the BSON representation of a plan rooted at 'root' is using * an index scan, and false otherwise. */function isIxscan(root) { return planHasStage(root, "IXSCAN");}/** * Returns true if the BSON representation of a plan rooted at 'root' is using * the idhack fast path, and false otherwise. */function isIdhack(root) { return planHasStage(root, "IDHACK");}/** * Returns true if the BSON representation of a plan rooted at 'root' is using * a collection scan, and false otherwise. */function isCollscan(root) { return planHasStage(root, "COLLSCAN");}/** * Get the number of chunk skips for the BSON exec stats tree rooted at 'root'. */function getChunkSkips(root) { if (root.stage === "SHARDING_FILTER") { return root.chunkSkips; } else if ("inputStage" in root) { return getChunkSkips(root.inputStage); } else if ("inputStages" in root) { var skips = 0; for (var i = 0; i < root.inputStages.length; i++) { skips += getChunkSkips(root.inputStages[0]); } return skips; }
mongo/jstests/concurrency/fsm_workloads/explain_count.js
$config.states = Object.extend({ explainBasicCount: function explainBasicCount(db, collName) { var res = db[collName].explain().count(); assertAlways.commandWorked(res); assertAlways(planHasStage(res.queryPlanner.winningPlan, 'COUNT')); }, explainCountHint: function explainCountHint(db, collName) { assertWhenOwnColl(function() { var res = db[collName].explain() .find({ i: this.nInserted / 2 }) .hint({ i: 1 }).count(); assertWhenOwnColl.commandWorked(res); assertWhenOwnColl(planHasStage(res.queryPlanner.winningPlan, 'COUNT')); assertWhenOwnColl(planHasStage(res.queryPlanner.winningPlan, 'COUNT_SCAN')); });
mongo/jstests/concurrency/fsm_workloads/explain_find.js
$config.states = Object.extend({ explainLimit: function explainLimit(db, collName) { var res = db[collName].find().limit(3).explain(); assertAlways.commandWorked(res); assertAlways(planHasStage(res.queryPlanner.winningPlan, 'LIMIT')); }, explainBatchSize: function explainBatchSize(db, collName) { var res = db[collName].find().batchSize(3).explain(); assertAlways.commandWorked(res); }, explainAddOption: function explainAddOption(db, collName) { var res = db[collName].explain().find().addOption(DBQuery.Option.exhaust).finish(); assertAlways.commandWorked(res); }, explainSkip: function explainSkip(db, collName) { var res = db[collName].explain().find().skip(3).finish(); assertAlways.commandWorked(res); assertAlways(planHasStage(res.queryPlanner.winningPlan, 'SKIP')); }, explainSort: function explainSort(db, collName) { var res = db[collName].find().sort({ i: -1 }).explain(); assertAlways.commandWorked(res); assertAlways(planHasStage(res.queryPlanner.winningPlan, 'SORT')); },
/** * The SubplanStage is used for rooted $or queries. It plans each clause of the $or * individually, and then creates an overall query plan based on the winning plan from * each clause. * * Uses the MultiPlanStage in order to rank plans for the individual clauses. * * Notes on caching strategy: * * --Interaction with the plan cache is done on a per-clause basis. For a given clause C, * if there is a plan in the cache for shape C, then C is planned using the index tags * obtained from the plan cache entry. If no cached plan is found for C, then a MultiPlanStage * is used to determine the best plan for the clause; unless there is a tie between multiple * candidate plans, the winner is inserted into the plan cache and used to plan subsequent * executions of C. These subsequent executions of shape C could be either as a clause in * another rooted $or query, or shape C as its own query. * * --Plans for entire rooted $or queries are neither written to nor read from the plan cache. */
allPlansExecution
顾名思义,allPlansExecution模式是将所有的执行计划均进行executionStats模式的操作,不在此赘述了。
后文
第二部分完。
以上便是explain的主要返回解析,那么,针对这么多返回项,我们应该关注什么呢?
在最后一部分中,我们将对该如何分析exlain信息进行详细解读,并将针对实例进行explain分析详解。
尽请期待。
- MongoDB干货系列2-MongoDB执行计划分析详解(2)
- MongoDB干货系列2-MongoDB执行计划分析详解(2)
- MongoDB干货系列2-MongoDB执行计划分析详解(2)
- MongoDB干货系列2-MongoDB执行计划分析详解(1)
- MongoDB干货系列2-MongoDB执行计划分析详解(1)
- MongoDB干货系列2-MongoDB执行计划分析详解(3)
- MongoDB干货系列2-MongoDB执行计划分析详解(1)
- MongoDB干货系列2-MongoDB执行计划分析详解(3)
- mongodb执行计划Explain分析实例(转载)
- MongoDB 性能优化:分析执行计划
- MongoDB 执行计划Explain
- mongodb查看执行计划
- MongoDB执行计划
- MongoDB DBA的日常巡检及执行计划分析
- MongoDB执行计划学习整理
- mongodb查询计划(explain)分析
- Mongodb 干货
- mongodb系列之-mongodb gridfs分析(java应用)
- Android CMake 使用Android Native library
- 欢迎使用CSDN-markdown编辑器
- 博客链接摘录
- disk i/o error
- 解决JavaScript库命名冲突问题 noConflict
- MongoDB干货系列2-MongoDB执行计划分析详解(2)
- react vr消息传递
- plsql developer 查询已经执行过的sql语句
- <NOIP> 22 . P1028 数的计算
- 解决ADB端口占用问题
- java中Map,List与Set详解
- 设计模式(六)观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)
- tcp_server和tcp_client
- Tomcat配置虚拟路径