mongodb查询操作分析
背景
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 操作
通过下面的语句,可以对当前查询计划展开分析
db.T_FooData.find({
"appId":"s5WrMmrJV_8RBJG17FSVoY995Kga",
"nodeType":"SENSOR",
"creationTime":{
$gte : ISODate("2017-08-08T10:34:33.125Z"),
$lt : ISODate("2017-08-08T12:34:33.125Z")
}
}).explain("executionStats")
输出结果
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "db.T_FooData",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"appId" : {
"$eq" : "s5WrMmrJV_8RBJG17FSVoY995Kga"
}
},
{
"nodeType" : {
"$eq" : "SENSOR"
}
},
{
"creationTime" : {
"$lt" : ISODate("2017-08-08T12:34:33.125Z")
}
},
{
"creationTime" : {
"$gte" : ISODate("2017-08-08T10:34:33.125Z")
}
}
]
},
"winningPlan" : { ... },
"rejectedPlans" : [ ... ],
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 62848,
"executionTimeMillis" : 3058,
"totalKeysExamined" : 1510833,
"totalDocsExamined" : 1510833,
"executionStages" : { ... }
},
"serverInfo" : {
"host" : "NB3000W_MongoDB_01",
"port" : 50001,
"version" : "3.4.7",
"gitVersion" : "4249c1d2b5999ebbf1fdf3bc0e0e3b3ff5c0aaf2"
},
"ok" : 1,
"$gleStats" : {
"lastOpTime" : Timestamp(1504498101, 1),
"electionId" : ObjectId("7fffffff0000000000000001")
}
}
结果说明
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 样例
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"nodeType" : {
"$eq" : "GATEWAY"
}
},
{
"creationTime" : {
"$lt" : ISODate("2017-08-08T12:34:33.125Z")
}
},
{
"creationTime" : {
"$gte" : ISODate("2017-08-08T10:34:33.125Z")
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"appId" : 1
},
"indexName" : "appId",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appId" : [
"[\"s5WrMmrJV_8RBJG17FSVoY995Kga\", \"s5WrMmrJV_8RBJG17FSVoY995Kga\"]"
]
}
}
},
字段说明
属性 | 描述 |
---|---|
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 样例
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 62848,
"executionTimeMillis" : 3058,
"totalKeysExamined" : 1510833,
"totalDocsExamined" : 1510833,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"nodeType" : {
"$eq" : "GATEWAY"
}
},
{
"creationTime" : {
"$lt" : ISODate("2017-08-08T12:34:33.125Z")
}
},
{
"creationTime" : {
"$gte" : ISODate("2017-08-08T10:34:33.125Z")
}
}
]
},
"nReturned" : 62848,
"executionTimeMillisEstimate" : 2765,
"works" : 1510834,
"advanced" : 62848,
"needTime" : 1447985,
"needYield" : 0,
"saveState" : 11807,
"restoreState" : 11807,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1510833,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1510833,
"executionTimeMillisEstimate" : 792,
"works" : 1510834,
"advanced" : 1510833,
"needTime" : 0,
"needYield" : 0,
"saveState" : 11807,
"restoreState" : 11807,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"appId" : 1
},
"indexName" : "appId",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appId" : [
"[\"s5WrMmrJV_8RBJG17FSVoY995Kga\", \"s5WrMmrJV_8RBJG17FSVoY995Kga\"]"
]
},
"keysExamined" : 1510833,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
字段说明
属性 | 描述 |
---|---|
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查询操作分析的更多相关文章
- 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 ...
- MongoDB查询操作限制返回字段的方法
这篇文章主要介绍了MongoDB查询操作限制返回字段的方法,需要的朋友可以参考下 映射(projection )声明用来限制所有查询匹配文档的返回字段.projection以文档的形式列举结果集中 ...
- mongodb查询文档
说到查询,我们一般就想起了关系型数据库的查询了,比如:order by(排序).limit(分页).范围查询(大于某个值,小于某个值..,in查询,on查询,like查询等待很多),同样mongodb ...
- [转]mongodb 查询条件:关系运算符"$lt", "$lte", "$gt", "$gte", "$ne" 逻辑运算符"$and“, "$or“, "$nor“
mongodb 查询条件 这节来说说mongodb条件操作符,"$lt", "$lte", "$gt", "$gte" ...
- Mongodb查询的用法,备注防止忘记
最近在用这个东西,为防止忘记,记下来. 集合简单查询方法 mongodb语法:db.collection.find() //collection就是集合的名称,这个可以自己进行创建. 对比sql语句 ...
- mongodb查询关于大于小于的用法;
mongoDB查询操作符: http://www.runoob.com/mongodb/mongodb-operators.html 项目中需要的场景是这样的,每个人每天只能领取一张明信片,换句话说, ...
- MongoDB查询分析
MongoDB 查询分析可以确保我们建立的索引是否有效,是查询语句性能分析的重要工具.MongoDB 查询分析常用函数有:explain() 和 hint(). 1. explain(): 提供查询信 ...
- 【mongodb系统学习之十】mongodb查询(一)
十.mongodb查询:find ;查询时条件中不能引用文档中其他键的值: 1).查询数据库全部数据:语法db.collectionName.find();默认只显示前20条,如图: 2).按条件查询 ...
- MongoDb进阶实践之三 MongoDB查询命令详述
一.引言 上一篇文章我们已经介绍了MongoDB数据库的最基本操作,包括数据库的创建.使用和删除数据库,文档的操作也涉及到了文档的创建.删除.更新和查询,当然也包括集合的创建.重命 ...
随机推荐
- 微信第三方全网发布接入检测(PHP)
官方文档 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&ve ...
- Java DB 访问之 mybatis mapper xml 配置方式
1 项目说明 项目采用 maven 组织 ,jdbc 唯一的依赖就是 mysql-connector-java pom 依赖如下: mysql 数据连接 : mysql-connector-java ...
- VSTS/TFS Auto Build
前几天使用VSTS配置自动部署前端网站(AngularJS)和RESTfulAPI(.NET)到客户环境. 由于都是参考官方文档 https://docs.microsoft.com/zh-cn/vs ...
- BZOJ3237: [Ahoi2013]连通图
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3237 cdq分治+缩点. 可以每次处理的时候把除l~r之外的边的端点都连起来.然后去跑cdq分 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- 机器学习笔记5-Tensorflow高级API之tf.estimator
前言 本文接着上一篇继续来聊Tensorflow的接口,上一篇中用较低层的接口实现了线性模型,本篇中将用更高级的API--tf.estimator来改写线性模型. 还记得之前的文章<机器学习笔记 ...
- 构建LVS-DR+Keepalive高可用集群
------client----------主LVS----------从LVS------------WEB1-------------WEB2--------- 2.2.2.250 2.2.2. ...
- [UWP]使用Reveal
1. 前言 之前在 如何使用Fluent Design System 这篇文章里已经简单介绍过Reveal的用法,这篇再详细介绍其它内容. 2. 自定义RevealButtonStyle 我觉得常用I ...
- Java map 详解 - 用法、遍历、排序、常用API等
尊重原创: http://www.cnblogs.com/lzq198754/p/5780165.html 概要: java.util 中的集合类包含 Java 中某些最常用的类.最常用的集合类是 L ...
- Entity framework 中Where、First、Count等查询函数使用时要注意
在.Net开发中,Entity framework是微软ORM架构的最佳官方工具.我们可以使用Lambda表达式在Entity framework中DbSet<T>类上直接做查询(比如使用 ...