背景

mongodb 提供了类sql的数据查询及操作方式,同时也包含了聚合操作、索引等多个机制;

按以往的经验,不当的库表操作或索引模式往往会造成许多问题,如查询操作缓慢、数据库吞吐量低下、CPU或磁盘IO飙升等问题。

因此在应用开发过程中,有必要对DB操作进行审视,尤其是关键业务或复杂条件查询。mongodb 提供了explain方法可以让我们

对 DB查询语句进行分析,提前分析潜在的瓶颈。

查询计划

mongodb 通过查询计划(QueryPlan)描述一个查询语句的执行过程,而通常一个查询操作可能对应多组查询计划。

这些查询计划通过选举机制产生最优计划,作为最终的执行方案。此外mongodb 还提供了查询计划的缓存机制,如下图:

https://docs.mongodb.com/manual/_images/query-planner-diagram.bakedsvg.sv

Diagram of query planner logic

查询操作被映射到一个查询模型(query shape),模型中会包含条件(predicate)、排序(sort)、投影(projection)的定义;

以查询模型作为Key查找已存在的Plan缓存,在找到缓存的下一步仍进一步评估查询性能,若性能评估结果未达标,则 mongodb会淘汰缓存并进入查询计划生成阶段。

每一个计划生成阶段都会包含:

  • 产生候选计划;
  • 评估优选计划;
  • 竞选最优计划;
  • 创建缓存;

在产生最优计划之后,查询执行器将执行当前计划并产生最终结果。

explain 操作

通过下面的语句,可以对当前查询计划展开分析

  1. db.T_FooData.find({
  2. "appId":"s5WrMmrJV_8RBJG17FSVoY995Kga",
  3. "nodeType":"SENSOR",
  4. "creationTime":{
  5. $gte : ISODate("2017-08-08T10:34:33.125Z"),
  6. $lt : ISODate("2017-08-08T12:34:33.125Z")
  7. }
  8. }).explain("executionStats")

输出结果

  1. {
  2. "queryPlanner" : {
  3. "plannerVersion" : 1,
  4. "namespace" : "db.T_FooData",
  5. "indexFilterSet" : false,
  6. "parsedQuery" : {
  7. "$and" : [
  8. {
  9. "appId" : {
  10. "$eq" : "s5WrMmrJV_8RBJG17FSVoY995Kga"
  11. }
  12. },
  13. {
  14. "nodeType" : {
  15. "$eq" : "SENSOR"
  16. }
  17. },
  18. {
  19. "creationTime" : {
  20. "$lt" : ISODate("2017-08-08T12:34:33.125Z")
  21. }
  22. },
  23. {
  24. "creationTime" : {
  25. "$gte" : ISODate("2017-08-08T10:34:33.125Z")
  26. }
  27. }
  28. ]
  29. },
  30. "winningPlan" : { ... },
  31. "rejectedPlans" : [ ... ],
  32. },
  33. "executionStats" : {
  34. "executionSuccess" : true,
  35. "nReturned" : 62848,
  36. "executionTimeMillis" : 3058,
  37. "totalKeysExamined" : 1510833,
  38. "totalDocsExamined" : 1510833,
  39. "executionStages" : { ... }
  40. },
  41. "serverInfo" : {
  42. "host" : "NB3000W_MongoDB_01",
  43. "port" : 50001,
  44. "version" : "3.4.7",
  45. "gitVersion" : "4249c1d2b5999ebbf1fdf3bc0e0e3b3ff5c0aaf2"
  46. },
  47. "ok" : 1,
  48. "$gleStats" : {
  49. "lastOpTime" : Timestamp(1504498101, 1),
  50. "electionId" : ObjectId("7fffffff0000000000000001")
  51. }
  52. }

结果说明

  • queryPlanner 描述当前的查询计划;

  • queryPlanner.namespace 描述当前的集合命名空间,{db}.{collectionName}

  • queryPlanner.indexFilterSet 是否设置了indexFilter,Filter决定了查询优化器对于某个查询将如何使用索引

  • queryPlanner.parsedQuery 解析后的查询信息

  • queryPlanner.winningPlan 最优计划

  • queryPlanner.rejectPlans 拒绝的计划列表

  • executionStats 执行过程统计,捕获计划在执行过程中的相关信息

  • executionStats.executionSuccess 是否执行成功

  • executionStats.nReturned 返回条目数量

  • executionStats.executionTimeMilis 执行时间(ms)

  • executionStats.totalKeysExamined 索引检测条目

  • executionStats.totalDocsExamined 文档检测条目

  • executionStats.executionStages 执行阶段详情

explain 模式

mongodb 为 explain 操作提供了几种模式:

  • queryPlanner 默认的模式,仅进行查询计划分析,无法输出执行过程统计;
  • executionStats 执行模式,在查询计划分析后,将执行winningPlan并统计过程信息;
  • allPlansExecution 全计划执行模式,将执行所有计划(包括rejectPlans),并返回过程统计信息;

    executionStats.allPlansExecution 包含了所有计划(除winningPlan之外)的执行过程统计信息

执行计划详解

执行计划将整个过程分解为多个阶段,阶段(stage)以树状结构组织,这点与执行过程是匹配的。

stage 分为多种类型,如下:

阶段 描述
COLLSCAN 全表扫描
IXSCAN 索引扫描
FETCH 根据索引去检索指定document
PROJECTION 限定返回字段
SHARD_MERGE 将各个分片返回数据进行merge
SORT 表明在内存中进行了排序
LIMIT 使用limit限制返回数
SKIP 使用skip进行跳过
IDHACK 针对_id进行查询
SHARDING_FILTER 通过mongos对分片数据进行查询
COUNT 利用db.coll.explain().count()之类进行count运算
COUNTSCAN count不使用用Index进行count
COUNT_SCAN count使用了Index进行count
SUBPLA 未使用到索引的$or查询
TEXT 使用全文索引进行查询

winningPlan 样例

  1. "winningPlan" : {
  2. "stage" : "FETCH",
  3. "filter" : {
  4. "$and" : [
  5. {
  6. "nodeType" : {
  7. "$eq" : "GATEWAY"
  8. }
  9. },
  10. {
  11. "creationTime" : {
  12. "$lt" : ISODate("2017-08-08T12:34:33.125Z")
  13. }
  14. },
  15. {
  16. "creationTime" : {
  17. "$gte" : ISODate("2017-08-08T10:34:33.125Z")
  18. }
  19. }
  20. ]
  21. },
  22. "inputStage" : {
  23. "stage" : "IXSCAN",
  24. "keyPattern" : {
  25. "appId" : 1
  26. },
  27. "indexName" : "appId",
  28. "isMultiKey" : false,
  29. "isUnique" : false,
  30. "isSparse" : false,
  31. "isPartial" : false,
  32. "indexVersion" : 1,
  33. "direction" : "forward",
  34. "indexBounds" : {
  35. "appId" : [
  36. "[\"s5WrMmrJV_8RBJG17FSVoY995Kga\", \"s5WrMmrJV_8RBJG17FSVoY995Kga\"]"
  37. ]
  38. }
  39. }
  40. },

字段说明

属性 描述
winningPlan.stage 最优计划stage,FETCH表示根据索引检索文档
winningPlan.filter 最优计划的过滤器,即查询条件
winningPlan.inputStage 最优计划stage的child stage
winningPlan.inputStage.stage child stage,此处是IXSCAN,表示进行index scanning
winningPlan.inputStage.keyPattern 扫描的索引模式
winningPlan.inputStage.indexName 选用索引名称
winningPlan.inputStage.isMultiKey 是否是Multikey,如果索引建立在array上则为true
winningPlan.inputStage.isSparse 是否稀疏索引
winningPlan.inputStage.isPartial 是否分区索引
winningPlan.inputStage.direction 此query的查询顺序,此处是forward,如果用了.sort({w:-1})将显示backward
winningPlan.inputStage.indexBounds 所扫描的索引范围

过程统计详解

executionStats 样例

  1. "executionStats" : {
  2. "executionSuccess" : true,
  3. "nReturned" : 62848,
  4. "executionTimeMillis" : 3058,
  5. "totalKeysExamined" : 1510833,
  6. "totalDocsExamined" : 1510833,
  7. "executionStages" : {
  8. "stage" : "FETCH",
  9. "filter" : {
  10. "$and" : [
  11. {
  12. "nodeType" : {
  13. "$eq" : "GATEWAY"
  14. }
  15. },
  16. {
  17. "creationTime" : {
  18. "$lt" : ISODate("2017-08-08T12:34:33.125Z")
  19. }
  20. },
  21. {
  22. "creationTime" : {
  23. "$gte" : ISODate("2017-08-08T10:34:33.125Z")
  24. }
  25. }
  26. ]
  27. },
  28. "nReturned" : 62848,
  29. "executionTimeMillisEstimate" : 2765,
  30. "works" : 1510834,
  31. "advanced" : 62848,
  32. "needTime" : 1447985,
  33. "needYield" : 0,
  34. "saveState" : 11807,
  35. "restoreState" : 11807,
  36. "isEOF" : 1,
  37. "invalidates" : 0,
  38. "docsExamined" : 1510833,
  39. "alreadyHasObj" : 0,
  40. "inputStage" : {
  41. "stage" : "IXSCAN",
  42. "nReturned" : 1510833,
  43. "executionTimeMillisEstimate" : 792,
  44. "works" : 1510834,
  45. "advanced" : 1510833,
  46. "needTime" : 0,
  47. "needYield" : 0,
  48. "saveState" : 11807,
  49. "restoreState" : 11807,
  50. "isEOF" : 1,
  51. "invalidates" : 0,
  52. "keyPattern" : {
  53. "appId" : 1
  54. },
  55. "indexName" : "appId",
  56. "isMultiKey" : false,
  57. "isUnique" : false,
  58. "isSparse" : false,
  59. "isPartial" : false,
  60. "indexVersion" : 1,
  61. "direction" : "forward",
  62. "indexBounds" : {
  63. "appId" : [
  64. "[\"s5WrMmrJV_8RBJG17FSVoY995Kga\", \"s5WrMmrJV_8RBJG17FSVoY995Kga\"]"
  65. ]
  66. },
  67. "keysExamined" : 1510833,
  68. "dupsTested" : 0,
  69. "dupsDropped" : 0,
  70. "seenInvalidated" : 0
  71. }
  72. }
  73. }

字段说明

属性 描述
executionStats.executionSuccess 是否执行成功
executionStats.nReturned 返回条目数量
executionStats.executionTimeMilis 执行时间(ms)
executionStats.totalKeysExamined 索引检测条目
executionStats.totalDocsExamined 文档检测条目
executionStats.executionStages 执行阶段详情,大部分字段继承于winningPlan.inputStage
executionStats.executionStages.stage 执行阶段,FETCH表示根据索引获取文档
executionStats.executionStages.nReturned 阶段返回条目数量
executionStats.executionStages.executionTimeMillisEstimate 阶段执行时间
executionStats.executionStages.docsExamined 阶段中文档检测条目
executionStats.executionStages.works 阶段中扫描任务数
executionStats.executionStages.advanced 阶段中向上提交数量
executionStats.executionStages.needTime 阶段中定位索引位置所需次数
executionStats.executionStages.needYield 阶段中获取锁等待时间
executionStats.executionStages.isEOF 阶段中是否到达流的结束位,对于limit限制符的查询可能为0
executionStats.executionStages.inputStage 执行阶段的子阶段,这里是一个IXSCAN的子过程

参考文档

explain 官方说明

http://www.mongoing.com/eshu_explain1

https://docs.mongodb.com/manual/reference/explain-results/#explain-output

关于explain的几种模式

https://docs.mongodb.com/manual/reference/method/cursor.explain/

理解mongo 的查询行为

https://www.compose.com/articles/explain-explain-understanding-mongo-query-behavior/

mongo的查询缓存

https://docs.mongodb.com/manual/core/query-plans/#index-filters

mongodb查询操作分析的更多相关文章

  1. MongoDB查询转对象是出错Element '_id' does not match any field or property of class

    MongoDB查询转对象是出错Element '_id' does not match any field or property of class   解决方法: 1.在实体类加:[BsonIgno ...

  2. MongoDB查询操作限制返回字段的方法

    这篇文章主要介绍了MongoDB查询操作限制返回字段的方法,需要的朋友可以参考下   映射(projection )声明用来限制所有查询匹配文档的返回字段.projection以文档的形式列举结果集中 ...

  3. mongodb查询文档

    说到查询,我们一般就想起了关系型数据库的查询了,比如:order by(排序).limit(分页).范围查询(大于某个值,小于某个值..,in查询,on查询,like查询等待很多),同样mongodb ...

  4. [转]mongodb 查询条件:关系运算符"$lt", "$lte", "$gt", "$gte", "$ne" 逻辑运算符"$and“, "$or“, "$nor“

    mongodb 查询条件   这节来说说mongodb条件操作符,"$lt", "$lte", "$gt", "$gte" ...

  5. Mongodb查询的用法,备注防止忘记

    最近在用这个东西,为防止忘记,记下来. 集合简单查询方法 mongodb语法:db.collection.find()  //collection就是集合的名称,这个可以自己进行创建. 对比sql语句 ...

  6. mongodb查询关于大于小于的用法;

    mongoDB查询操作符: http://www.runoob.com/mongodb/mongodb-operators.html 项目中需要的场景是这样的,每个人每天只能领取一张明信片,换句话说, ...

  7. MongoDB查询分析

    MongoDB 查询分析可以确保我们建立的索引是否有效,是查询语句性能分析的重要工具.MongoDB 查询分析常用函数有:explain() 和 hint(). 1. explain(): 提供查询信 ...

  8. 【mongodb系统学习之十】mongodb查询(一)

    十.mongodb查询:find ;查询时条件中不能引用文档中其他键的值: 1).查询数据库全部数据:语法db.collectionName.find();默认只显示前20条,如图: 2).按条件查询 ...

  9. MongoDb进阶实践之三 MongoDB查询命令详述

    一.引言           上一篇文章我们已经介绍了MongoDB数据库的最基本操作,包括数据库的创建.使用和删除数据库,文档的操作也涉及到了文档的创建.删除.更新和查询,当然也包括集合的创建.重命 ...

随机推荐

  1. Django之cookie验证

    先不用太多的蚊子描述什么是cookie,先做一个小实验: 此时我们在谷歌浏览器(一个客户端)和IE浏览器(另一个用户)测试: 刺客我们发现在两台浏览器都可以访问,而且不用进入login验证就可以登录, ...

  2. .net的retrofit--WebApiClient底层篇

    前言 本篇文章的内容是WebApiClient底层说明,也是WebApiClient系列接近尾声的一篇文章,如果你没有阅读过之前的的相关文章,可能会觉得本文章的内容断层,WebApiClient系列文 ...

  3. 浴室沉思:聊聊DAL和Repository

    这是一个由DDD群引发的随笔 在写了上一篇随笔<关于ORM的浴室沉思>后一些朋友私聊我,很多刚接触DDD的朋友会对Repository(仓储层)这东西有点疑惑,为什么要叫仓储层?是不是三层 ...

  4. Java面向对象抽象类案例分析

    /** 雇员示例: 需求:公司中程序员有姓名,工号,薪水,工作内容 项目经理除了有姓名,工号,薪水还有奖金,工作内容 对给出需求进行数据建模 分析: 在这个问题领域中,先找出涉及的对象 通过名词提炼法 ...

  5. Codeforces Round #449 (Div. 2)-897A.Scarborough Fair(字符替换水题) 897B.Chtholly's request(处理前一半) 897C.Nephren gives a riddle(递归)

    A. Scarborough Fair time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  6. net+Oracle开发过程中遇到的小问题

    最新的项目开始使用Oracle后,5个月之间遇到一些在SqlServer中没有遇到的问题,这里记录并贴上一些常用的解决办法. Oracle相关 一.数据库不同版本还原: 刚开始我们一直使用Oracle ...

  7. c++只能编译无法运行或许缺少命令

    -mwindows -lcomctl32 -lwinmm -lws2_32 -lodbc32 -lmysql   -lwinspool1.工具-编译选项-编译器-在连接器命令行加入以下命令:-mwin ...

  8. [学习OpenCV攻略][006][平滑图片]

    cvCreateImage(图片大小,像素位数,通道数) 创建图片,根据输入的图片大小,各个通道像素点的位数,和通道数.像素点宏IPL_DEPTH_8U cvGetSize(图片) 得到图片的大小信息 ...

  9. 关于Swing窗体有时候要放大缩小边框才能显示问题?

    有时候会出现编写swing窗体后添加的组件在run之后显示不出来的问题.如图: 搜了下解决办法.此时如果是程序里面有panel组件的话,应该这样: labels[i] = new Label(lett ...

  10. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...