一个MongoDB索引走偏的案例及探究分析
接业务需求,有一个MongoDB的简单查询,太耗时了,执行了 70S 左右,严重影响用户的体验。。
查询代码主要如下:
db.duoduologmodel.find({"Tags.SN": "QZ435698245"})
.projection({})
.sort({OPTime: -})
.limit(20)
此集合在字段OPTime上有索引idx_OPTime;在"Tags"数组中的内嵌字段"SN"有索引idx_TSN;两者都是独立的索引。此集合存放的是执行Log,相对Size较大。
查看此查询对应的慢查询日志,如下:
--13T15::16.767+ I COMMAND [conn536359] command shqq_zp.duoduologmodel command: find { find: "duoduologmodel", filter: { Tags.SN: "QZ435698245" }, sort: { OPTime: - }, projection: {}, limit: , $db: "shqq_zp", $clusterTime: { clusterTime: Timestamp(, ), signature: { hash: BinData(, E7B0A887E83BAD0AA0A72016A39C677B53ABDBE2), keyId: } }, lsid: { id: UUID("0f22409b-f122-41e9-a094-46ccf04e44c7") } } planSummary: IXSCAN { OPTime: } cursorid: keysExamined: docsExamined: fromMultiPlanner: replanned: numYields: nreturned: reslen: locks:{ Global: { acquireCount: { r: } }, Database: { acquireCount: { r: } }, Collection: { acquireCount: { r: } } } protocol:op_msg 692537ms
查看此查询的执行计划,执行代码
db.duoduologmodel.find({"Tags.SN": "QZ435698245"})
.projection({})
.sort({OPTime: -})
.explain()
主要反馈信息
"queryPlanner" : {
"plannerVersion" : ,
"namespace" : "shqq_zp.duoduologmodel",
"indexFilterSet" : false,
"parsedQuery" : {
"Tags.SN" : {
"$eq" : "QZ435698245"
}
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"OPTime" : -
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Tags.SN" :
},
"indexName" : "idx_TSN",
"isMultiKey" : true,
"multiKeyPaths" : {
"Tags.SN" : [
"Tags"
]
},
"isUnique" : false,
"isSparse" : true,
"isPartial" : false,
"indexVersion" : ,
"direction" : "forward",
"indexBounds" : {
"Tags.SN" : [
"[\"QZ435698245\", \"QZ435698245\"]"
]
}
}
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"Tags.SN" : {
"$eq" : "QZ435698245"
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"OPTime" :
},
"indexName" : "idx_OPTime",
"isMultiKey" : false,
"multiKeyPaths" : {
"OPTime" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : ,
"direction" : "backward",
"indexBounds" : {
"OPTime" : [
"[MaxKey, MinKey]"
]
}
}
}
]
}
假如不用排序,删除 .sort({OperationTime: -1}),其执行计划
"queryPlanner" : {
"plannerVersion" : ,
"namespace" : "shqq_zp.duoduologmodel",
"indexFilterSet" : false,
"parsedQuery" : {
"Tags.SN" : {
"$eq" : "QZ435698245"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Tags.SN" :
},
"indexName" : "idx_TSN",
"isMultiKey" : true,
"multiKeyPaths" : {
"Tags.SN" : [
"Tags"
]
},
"isUnique" : false,
"isSparse" : true,
"isPartial" : false,
"indexVersion" : ,
"direction" : "forward",
"indexBounds" : {
"Tags.SN" : [
"[\"QZ435698245\", \"QZ435698245\"]"
]
}
}
},
"rejectedPlans" : [ ]
}
此时,执行查询确实变快了很多,在2S以内执行完毕。
删除OPTime字段索引后的执行计划
"queryPlanner" : {
"plannerVersion" : ,
"namespace" : "shqq_zp.duoduologmodel",
"indexFilterSet" : false,
"parsedQuery" : {
"Tags.SN" : {
"$eq" : "QZ435698245"
}
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"OPTime" : -
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Tags.SN" :
},
"indexName" : "idx_TSN",
"isMultiKey" : true,
"multiKeyPaths" : {
"Tags.SN" : [
"Tags"
]
},
"isUnique" : false,
"isSparse" : true,
"isPartial" : false,
"indexVersion" : ,
"direction" : "forward",
"indexBounds" : {
"Tags.SN" : [
"[\"QZ435698245\", \"QZ435698245\"]"
]
}
}
}
}
},
"rejectedPlans" : [ ]
}
删除这个索引后,查看报错
{
"message" : "Executor error during find command :: caused by :: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.",
"OPTime" : "Timestamp(1565681389, 1)",
"ok" : ,
"code" : ,
"codeName" : "OperationFailed",
"$clusterTime" : {
"clusterTime" : "Timestamp(1565681389, 1)",
"signature" : {
"hash" : "vODWe0BCzyihrRVM08wPSFIMvo0=",
"keyId" : ""
}
},
"name" : "MongoError"
}
原因比较明确:Sort operation used more than the maximum 33554432 bytes of RAM.,33554432 bytes算下来正好是32Mb,而Mongodb的sort操作是把数据拿到内存中再进行排序的,为了节约内存,默认给sort操作限制了最大内存为32Mb,当数据量越来越大直到超过32Mb的时候就自然抛出异常了!
因这个查看功能执行不多,并发不高。将系统排序内存由默认的32M调整到64M。
(此操作需谨慎,一般不建议修改,需要结合业务的使用情况,比如并发,数据量的大小;应优先考虑通过调整索引或集合的设计、甚至前端的设计来实现优化。)
db.adminCommand({setParameter:, internalQueryExecMaxBlockingSortBytes:})
(注意;这个设置在重启MongoDB服务就会失效,重新变成默认的32M了)。
再次执行查询查看,不再报错。并且快速返回结果(2S)
因为还有其他需求,会根据OPTime字段查看,重新添加这个索引。
再次执行,也可以比较迅速的返回结果(2S)。
从以上分析我们可以推断;
(1)explain()查看的执行计划,有时候还是有偏差的。
(2)Sort排序情况会影响索引的选择。即当internalQueryExecMaxBlockingSortBytes不足以支持先查询(by tag.sn)后排序(by optime)时,系统自动选择了一个已排序好的索引(by optime),进行查看。
知识补充:
queryPlanner.namespace:该值返回的是该query所查询的表;
queryPlanner.indexFilterSet:针对该query是否有indexfilter;
queryPlanner.winningPlan:查询优化器针对该query所返回的最优执行计划的详细内容;
queryPlanner.rejectedPlans:其他执行计划(非最优而被查询优化器reject的)的详细返回。
本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!
本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!
本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!
一个MongoDB索引走偏的案例及探究分析的更多相关文章
- 【四】MongoDB索引管理
一.索引介绍 在mongodb中,索引用来支持高效查询.如果没有索引,mongodb必须在整个集合中扫描每个文档来查找匹配的文档.但是如果建立合适的索引,mongodb就可以通过索引来限制检查的文档数 ...
- Mongodb索引和执行计划 hint 慢查询
查询索引 索引存放在system.indexes集合中 > show tables address data person system.indexes 默认会为所有的ID建上索引 而且无法删除 ...
- MongoDB索引的简单理解
目录 MongoDB索引 1.语法准备 2.数据准备: 3.索引 3.1 唯一索引 3.2 单键索引 3.3 多键索引 3.4 复合索引 3.5 交叉索引 3.6 部分索引 3.7覆盖索引 3.8 全 ...
- [DataBase] MongoDB (7) MongoDB 索引
MongoDB 索引 1. 建立索引 唯一索引db.passport.ensureIndex( {"loginname": 1}, {"unique": tru ...
- MongoDB索引介绍
MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致.由于集合中的键(字段)可以是普通数据类型,也可以是子文档.MongoDB可以在各种类型的键上创建索 ...
- MongoDB(索引及C#如何操作MongoDB)(转载)
MongoDB(索引及C如何操作MongoDB) 索引总概况 db.test.ensureIndex({"username":1})//创建索引 db.test.ensureInd ...
- BuguMongo是一个MongoDB Java开发框架,集成了DAO、Query、Lucene、GridFS等功能
http://code.google.com/p/bugumongo/ 简介 BuguMongo是一个MongoDB Java开发框架,它的主要功能包括: 基于注解的对象-文档映射(Object-Do ...
- MongoDB学习笔记(六) MongoDB索引用法和效率分析
MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致.由于集合中的键(字段)可以是普通数据类型,也可以是子文档.MongoDB可以在各种类型的键上创建索 ...
- MongoDB索引(一)
原文地址 一.介绍 我们已经很清楚索引会提高查询效率.如果没有索引,MongoDB必须对全部集合进行扫描,即,扫描集合中每条文档以选择那些符合查询条件的文档.对查询来说如果存在合适的索引,则Mongo ...
随机推荐
- MongoDB第三天(正则,管道,聚合,字符串,算术,日期,java连接MongoDB)
部分正则表达式: i:忽略大小写 m:多行查找 x:设置 x 选项后,正则表达式中的非转义的空白字符将被忽略. s:允许点字符(即.)匹配包括换行符在内的所有字符. w:匹配包括下划线的任何单词字 ...
- openlayers4 入门开发系列结合 echarts4 实现交通线流动图
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】
Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...
- LCT(Link Cut Tree)总结
概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...
- zabbix4.0.1 安装部署
zabbix安装部署 目录 一.环境准备... 3 1.1.版本:... 3 1.2.部署环境... 3 二.安装部署... 3 2.1.zabbix安装... 3 2.1.1.下载zabbix的rp ...
- Java并发编程系列-(2) 线程的并发工具类
2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...
- Selenium之xpath绝对路径表示法
xpath写法: 绝对路径:以/开始,逐个增加节点用/分割 特点:不能跨级.类似css中的直接子元素选择器 相对路径:用两个斜杠 // 如 //div//p//a 通配符:xpath也有 ...
- 《项目实战》从Spring开始说起
引导 从今天开始,我们正式进入项目实战系列,我们会从项目架构的搭建,以及如何解决三高问题(高并发.高可用.高性能),源码会同步进行更新,欢迎大家持续关注 https://gitee.com/liupa ...
- 大数据学习笔记——Java篇之集合框架(ArrayList)
Java集合框架学习笔记 1. Java集合框架中各接口或子类的继承以及实现关系图: 2. 数组和集合类的区别整理: 数组: 1. 长度是固定的 2. 既可以存放基本数据类型又可以存放引用数据类型 3 ...
- python之with语句结合上下文管理器
所谓上下文管理器即在一个类中重写了__enter__方法和__exit__方法的类就可以成为上下文管理器类. 我们可以通过with语句结合上下文管理器简化一些操作. 使用with语句结合自定义上下文管 ...