要保证数据库处于高效、稳定的状态,除了良好的硬件基础、高效高可用的数据库架构、贴合业务的数据模型之外,高效的查询语句也是不可少的。那么,如何查看并判断我们的执行计划呢?我们今天就来谈论下MongoDB的执行计划分析。

引子
MongoDB 3.0之后,explain的返回与使用方法与之前版本有了不少变化,介于3.0之后的优秀特色,本文仅针对MongoDB 3.0+的explain进行讨论。

现版本explain有三种模式,分别如下:

queryPlanner

executionStats

allPlansExecution

由于文章字数原因,本系列将分为三个部分。

本文是第一部分,主要针对queryPlanner,与executionStats进行分析。

正文
queryPlanner

queryPlanner是现版本explain的默认模式,queryPlanner模式下并不会去真正进行query语句查询,而是针对query语句进行执行计划分析并选出winning plan。

<code>{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "game_db.game_user",
"indexFilterSet" : false,
"parsedQuery" : {
"w" : {
"$eq" : 1
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"w" : 1,
"n" : 1
},
"indexName" : "w_1_n_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"w" : [
"[1.0, 1.0]"
],
"n" : [
"[MinKey, MaxKey]"
]
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"w" : 1,
"v" : 1
},
"indexName" : "w_1_v_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"w" : [
"[1.0, 1.0]"
],
"v" : [
"[MinKey, MaxKey]"
]
}
}
}
]
},
</code>
先来看queryPlanner模式的各个返回意义。

explain.queryPlanner

queryPlanner的返回。

explain.queryPlanner.namespace

顾名思义,该值返回的是该query所查询的表。

explain.queryPlanner.indexFilterSet

针对该query是否有indexfilter(会在后文进行详细解释)。

explain.queryPlanner.winningPlan

查询优化器针对该query所返回的最优执行计划的详细内容。

explain.queryPlanner.winningPlan.stage

最优执行计划的stage,这里返回是FETCH,可以理解为通过返回的index位置去检索具体的文档(stage有数个模式,将在后文中进行详解)。

explain.queryPlanner.winningPlan.inputStage

explain.queryPlanner.winningPlan.stage的child stage,此处是IXSCAN,表示进行的是index scanning。

explain.queryPlanner.winningPlan.keyPattern

所扫描的index内容,此处是w:1与n:1。

explain.queryPlanner.winningPlan.indexName

winning plan所选用的index。

explain.queryPlanner.winningPlan.isMultiKey

是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。

explain.queryPlanner.winningPlan.direction

此query的查询顺序,此处是forward,如果用了.sort({w:-1})将显示backward。

explain.queryPlanner.winningPlan.indexBounds

winningplan所扫描的索引范围,此处查询条件是w:1,使用的index是w与n的联合索引,故w是[1.0,1.0]而n没有指定在查询条件中,故是[MinKey,MaxKey]。

explain.queryPlanner.rejectedPlans

其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述。

executionStats

executionStats的返回中多了如下:

<code> "executionStats" : {
"executionSuccess" : true,
"nReturned" : 29861,
"executionTimeMillis" : 23079,
"totalKeysExamined" : 29861,
"totalDocsExamined" : 29861,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 29861,
"executionTimeMillisEstimate" : 22685,
"works" : 29862,
"advanced" : 29861,
"needTime" : 0,
"needFetch" : 0,
"saveState" : 946,
"restoreState" : 946,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 29861,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 29861,
"executionTimeMillisEstimate" : 70,
"works" : 29862,
"advanced" : 29861,
"needTime" : 0,
"needFetch" : 0,
"saveState" : 946,
"restoreState" : 946,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"w" : 1,
"n" : 1
},
"indexName" : "w_1_n_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"w" : [
"[1.0, 1.0]"
],
"n" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 29861,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0
}
}
},
</code>
executionStats模式中,我们主要需要注意的返回有如下几个

executionStats.executionSuccess

是否执行成功

executionStats.nReturned

查询的返回条数

executionStats.executionTimeMillis

整体执行时间

executionStats.totalKeysExamined

索引扫描次数

executionStats.totalDocsExamined

document扫描次数

以上几个非常好理解,我们就不在这里详述,后文的案例中会有分析。

executionStats.executionStages.stage

这里是FETCH去扫描对于documents

executionStats.executionStages.nReturned

由于是FETCH,所以这里该值与executionStats.nReturned一致

executionStats.executionStages.docsExamined

与executionStats.totalDocsExamined一致

executionStats.inputStage中的与上述理解方式相同

还有一些文档中没有描述的返回如:

“works” : 29862,

“advanced” : 29861,

“isEOF” : 1,

这些值都会在explan之初初始化:

mongo/src/mongo/db/exec/plan_stats.h

<code>struct CommonStats {
CommonStats(const char* type)
: stageTypeStr(type),
works(0),
yields(0),
unyields(0),
invalidates(0),
advanced(0),
needTime(0),
needYield(0),
executionTimeMillis(0),
isEOF(false) {}
</code>
以works为例,查看源码中发现,每次操作会加1,且会把执行时间记录在executionTimeMillis中。

mongo/src/mongo/db/exec/fetch.cpp

<code> ++_commonStats.works;

// Adds the amount of time taken by work() to executionTimeMillis.
ScopedTimer timer(&_commonStats.executionTimeMillis);
</code>
而在查询结束EOF,works又会加1,advanced不加。

mongo/src/mongo/db/exec/eof.cpp

<code>PlanStage::StageState EOFStage::work(WorkingSetID* out) {
++_commonStats.works;
// Adds the amount of time taken by work() to executionTimeMillis.
ScopedTimer timer(&_commonStats.executionTimeMillis);
return PlanStage::IS_EOF;
}
</code>
故正常的返回works会比nReturned多1,这时候isEOF为true(1):

mongo/src/mongo/db/exec/eof.cpp

<code>bool EOFStage::isEOF() {
return true;
}

unique_ptr<PlanStageStats> EOFStage::getStats() {
_commonStats.isEOF = isEOF();
return make_unique<PlanStageStats>(_commonStats, STAGE_EOF);
}

</code>
advanced的返回值在命中的时候+1,在skip,eof的时候不会增加如:

mongo/src/mongo/db/exec/skip.cpp

<code>if (PlanStage::ADVANCED == status) {
// If we're still skipping results...
if (_toSkip > 0) {
// ...drop the result.
--_toSkip;
_ws->free(id);
++_commonStats.needTime;
return PlanStage::NEED_TIME;
}

*out = id;
++_commonStats.advanced;
return PlanStage::ADVANCED;
</code>

MongoDB执行计划分析详解的更多相关文章

  1. MongoDB干货系列2-MongoDB执行计划分析详解(2)(转载)

    写在之前的话 作为近年最为火热的文档型数据库,MongoDB受到了越来越多人的关注,但是由于国内的MongoDB相关技术分享屈指可数,不少朋友向我抱怨无从下手. <MongoDB干货系列> ...

  2. SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)

    接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...

  3. MySQL 执行计划explain详解

    MySQL 执行计划explain详解 2015-08-10 13:56:27 分类: MySQL explain命令是查看查询优化器如何决定执行查询的主要方法.这个功能有局限性,并不总会说出真相,但 ...

  4. SQL Server 执行计划操作符详解(2)——串联(Concatenation )

    本文接上文:SQL Server 执行计划操作符详解(1)--断言(Assert) 前言: 根据计划,本文开始讲述另外一个操作符串联(Concatenation),读者可以根据这个词(中英文均可)先幻 ...

  5. MYSQL EXPLAIN执行计划命令详解(支持更新中)

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 本篇是根据官网中的每个一点来翻译.举例.验证的:英语不好,所 ...

  6. SQL Server 执行计划操作符详解(1)——断言(Assert)

    前言: 很多很多地方对于语句的优化,一般比较靠谱的回复即使--把执行计划发出来看看.当然那些只看语句就说如何如何改代码,我一直都是拒绝的,因为这种算是纯蒙.根据本人经验,大量的性能问题单纯从语句来看很 ...

  7. 0912MySQL 执行计划explain详解

    转自http://blog.itpub.net/29773961/viewspace-1767044/ 该博客内容是比较全的,虽然写的比较晦涩,多读几遍还是不错的 explain命令是查看查询优化器如 ...

  8. 学习计划 mysql explain执行计划任务详解

    我们在之前已经找到了需要优化的SQL,但是怎么知道它的那些方面需要优化呢? explain就是为了这个使用的. explain显示了 mysql 如何使用索引来处理select语句以及连接表.可以帮助 ...

  9. MongoDB各种查询操作详解

    这篇文章主要介绍了MongoDB各种查询操作详解,包括比较查询.关联查询.数组查询等,需要的朋友可以参考下   一.find操作 MongoDB中使用find来进行查询,通过指定find的第一个参数可 ...

随机推荐

  1. POI插件使用读取office文件

    html文件代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> & ...

  2. CodeForces 671A Recycling Bottles

    暴力. 每个人找到一个入口,也就是从回收站到这个入口走的路程由人的位置到入口的路程来替代. 因此,只要找两个人分别从哪里入口就可以了.注意:有可能只要一个人走,另一人不走. #pragma comme ...

  3. [SOJ]统计数字

    Description 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小 ...

  4. HUD 1171 Big Event in HDU(01背包)

    Big Event in HDU Problem Description Nowadays, we all know that Computer College is the biggest depa ...

  5. php 学习之对象

    php中怎么实现创建一个对象然后全局都能调用? 在PHP中相当常见的一种情形时,我们只需要创建一个对象一次,然后在我们的整个程序中使用它.一个很好的例子就是smarty变量,一旦被初始化后就可以在任何 ...

  6. 四步安装typecho(LNMP环境)

    ##1 安装nginx,mysql,php环境 sudo apt-get install nginx php5-fpm php5-cgi php5-cli php5-curl php5-gd php5 ...

  7. Python基础篇-day11 - 协程

    本节主要内容: 1.Gevent协程2.Select\Poll\Epoll异步IO与事件驱动3.RabbitMQ队列 1.Gevent协程 1.1协程的好处 无需线程上下文切换的开销无需原子操作锁定及 ...

  8. Android:自定义Dialog大小,显示圆角

    经过测试,可以使用. ----------------------------------------------------------- AlertDialog.Builder builder = ...

  9. java中String类型的相关知识

    String类方法整理说明: ·Length()用来求字符串的长度,返回值为字符串的长度: ·charAt()取该字符串某个位置的字符,从0开始,为char类型: ·getChars()将这个字符串中 ...

  10. XOR and Favorite Number(莫队算法+分块)

    E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...