MongoDB 性能优化之索引优化
索引是用来加快查询速度的,事物都有双面性的,同时在每次插入、更新和删除操作时都会产生额外的开销。索引有时并不能解决查询慢的问题,一般来说,返回集合中一半以上的结果,全表扫描要比查询索引更高效些。创建太多索引,会导致插入非常慢,同时还会占用很大空间。可以通过一些工具来分析查询的效率来进一步优化索引。
一、MongoDB自带工具explain
使用explain命令返回查询使用的索引情况,耗时,扫描文档数等等统计信息。
cursor:返回游标类型
isMultiKey:是否使用组合索引
n:返回文档数量
nscannedObjects:被扫描的文档数量
nscanned:被检查的文档或索引条目数量
scanAndOrder:是否在内存中排序
indexOnly:
nYields:该查询为了等待写操作执行等待的读锁的次数
nChunkSkips:
millis:耗时(毫秒)
indexBounds:所使用的索引
server: 服务器主机名
可以结合hint强制使用索引来分析。
二、开启profiling功能,设置日志级别,对日志进行分析
1.查看profiling级别:
>db.getProfilingLevel()
2.设置profiling级别:
语法:db.setProfilingLevel(level,slowms)
level - profile的级别可以取0,1,2 表示的意义如下:
#0 - 关闭性能分析,测试环境可以打开,生成环境关闭,对性能有很大影响;
#1 - 开启慢查询日志,执行时间大于100毫秒的语句
#2 - 开启所有操作日志
slowms - 慢查询时间阀值,默认100ms
MongoDB Profile 记录是直接存在系统 db 里的,记录位置system.profile 。
ts: 该命令在何时执行
op: 操作类型
query: 本命令的详细信息
responseLength: 返回结果集的大小
ntoreturn: 本次查询实际返回的结果集
millis: 该命令执行耗时,以毫秒记
4.修改profiling大小
capped Collections 比普通Collections 的读写效率高。Capped Collections 是高效率的Collection类型,它有如下特点:
a. 固定大小;Capped Collections 必须事先创建,并设置大小:
> db.createCollection("collection", {capped:true, size:100000})
b. Capped Collections 可以insert 和update 操作,不能delete 操作。只能用drop()方法删除整个Collection。
c. 默认基于Insert 的次序排序的。如果查询时没有排序,则总是按照insert 的顺序返回。
d. FIFO。如果超过了Collection 的限定大小,则用FIFO 算法,新记录将替代最先insert的记录
三、查询分析器—dex
mongodb索引和查询分析器dex,是一种MongoDB的性能调整工具,比较MongoDB的日志文件和索引条目并给出索引建议。目前,必须提供一个连接数据库的URI。dex只建议完整的索引,而不是部分索引。不支持Windows平台。dex在运行过程中主要会进行下面三个步骤:
1.解析query
2.通过已存在的索引对当前query进行判断
3.如果发现索引不当,就推荐合适的索引。
第一步:解析query
Dex会对查询query进行解析,分成下面几大类
EQUIV – 普通按数值进行的查询,比如:{a: 1}
SORT – sort操作,比如: .sort({a: 1})
RANGE – 范围查询,比如:Specifically: ‘$ne’, ‘$gt’, ‘$lt’, ‘$gte’, ‘$lte’, ‘$in’, ‘$nin’, ‘$all’, ‘$not’
UNSUPPORTED
组合式查询,比如:$and, $or, $nor
除了RANGE之外的嵌套查询
第二步:判断当前索引情况
有两个标准来找出查询所需的索引。
Coverage (none, partial, full) - Coverage表示索引的情况,有括号中的三个值。none表示完全无索引覆盖。full表示query中的字段都能找到索引。partial表示none和full之间的情况。
Order (ideal or not) - Order是用于判断索引的顺序是否理想。理想的索引顺序应该是: Equivalence ○ Sort ○ Range 值得注意的是,对地理位置索引只会进行分析,但是不会提出改进建议。
第三步:推荐合适的索引
通过上面两步,我们能够对一个查询可能使用索引的情况有一个了解。Dex会生成一个此查询的最佳索引。如果这个索引不存在,并且查询情况不包括上面提到的UNSUPPORTED,那么Dex就会做出相应的索引优化建议。
具体使用参考:http://www.ttlsa.com/mongodb/mongodb-index-and-query-analyzer-tools-dex/
使用explain命令返回查询使用的索引情况,耗时,扫描文档数等等统计信息。
> db.user.find({name:/^zhangsan2*2$/,index:{"$lt":299190}}).explain(); { "cursor" : "BasicCursor", "isMultiKey" : false, "n" : 6, "nscannedObjects" : 2000000, "nscanned" : 2000000, "nscannedObjectsAllPlans" : 2000000, "nscannedAllPlans" : 2000000, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 1, "nChunkSkips" : 0, "millis" : 1240, "indexBounds" : { }, "server" : "100.205:27017" }字段说明:
cursor:返回游标类型
isMultiKey:是否使用组合索引
n:返回文档数量
nscannedObjects:被扫描的文档数量
nscanned:被检查的文档或索引条目数量
scanAndOrder:是否在内存中排序
indexOnly:
nYields:该查询为了等待写操作执行等待的读锁的次数
nChunkSkips:
millis:耗时(毫秒)
indexBounds:所使用的索引
server: 服务器主机名
可以结合hint强制使用索引来分析。
二、开启profiling功能,设置日志级别,对日志进行分析
1.查看profiling级别:
>db.getProfilingLevel()
2.设置profiling级别:
语法:db.setProfilingLevel(level,slowms)
level - profile的级别可以取0,1,2 表示的意义如下:
#0 - 关闭性能分析,测试环境可以打开,生成环境关闭,对性能有很大影响;
#1 - 开启慢查询日志,执行时间大于100毫秒的语句
#2 - 开启所有操作日志
slowms - 慢查询时间阀值,默认100ms
>db.setProfilingLevel(1,100) { "was" : 0, "slowms" : 100, "ok" : 1 } >db.setProfilingLevel(0)3.查询profiling记录
MongoDB Profile 记录是直接存在系统 db 里的,记录位置system.profile 。
> db.system.profile.find().sort({$natural:-1}).limit(1) { "ts": ISODate("2015-03-19T08:42:51.012Z"), "op": "query", "ns": "test.system.profile", "query": { "query": { }, "orderby": { "$natural": -1 } }, "ntoreturn": 1, "ntoskip": 0, "nscanned": 1, "keyUpdates": 0, "numYield": 0, "lockStats": { "timeLockedMicros": { "r": NumberLong(118), "w": NumberLong(0) }, "timeAcquiringMicros": { "r": NumberLong(6), "w": NumberLong(4) } }, "nreturned": 1, "responseLength": 385, "millis": 0, "client": "127.0.0.1", "user": "" }参数介绍: ts:操作执行时的时间戳 millis:执行操作所花的时间 query:数据库查询操作,查询字段信息包括ntoreturn,query,nscanned,reslen,nreturned ntoreturn:从查询中返回客户端指定的对象数 query:查询操作信息 nscanned:在执行查询操作的时候扫描了多少对象 reslen:查询结果的大小 nreturned:从查询中返回的结果对象 update:数据库更新操作, insert:数据库插入操作 getmore:大数据量查询 查询优化: 1、如果nscanned 比 nreturned 大很多时,说明数据库扫描了很大对象才找到目标对象,因此需要为条件查询创建索引 2、当返回的结果集很大时即reslen值相当大时,会影响性能下降,在做find查询时,需要添加第二个查询参数,只获取需要显示的字段 参考:http://www.cnblogs.com/DxSoft/archive/2010/10/21/1857357.html
> db.system.profile.find().pretty().limit(1) { "ts" : ISODate("2015-03-19T08:36:13.451Z"), "op" : "command", "ns" : "test.$cmd", "command" : { "profile" : 2, "slowms" : 100 }, "ntoreturn" : 1, "keyUpdates" : 0, "numYield" : 0, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(0), "w" : NumberLong(18) }, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(7) } }, "responseLength" : 58, "millis" : 0, "client" : "127.0.0.1", "user" : "" }字段说明:
ts: 该命令在何时执行
op: 操作类型
query: 本命令的详细信息
responseLength: 返回结果集的大小
ntoreturn: 本次查询实际返回的结果集
millis: 该命令执行耗时,以毫秒记
4.修改profiling大小
capped Collections 比普通Collections 的读写效率高。Capped Collections 是高效率的Collection类型,它有如下特点:
a. 固定大小;Capped Collections 必须事先创建,并设置大小:
> db.createCollection("collection", {capped:true, size:100000})
b. Capped Collections 可以insert 和update 操作,不能delete 操作。只能用drop()方法删除整个Collection。
c. 默认基于Insert 的次序排序的。如果查询时没有排序,则总是按照insert 的顺序返回。
d. FIFO。如果超过了Collection 的限定大小,则用FIFO 算法,新记录将替代最先insert的记录
> db.setProfilingLevel(0) { "was" : 2, "slowms" : 100, "ok" : 1 } > db.getProfilingLevel() 0 > db.system.profile.drop() true > db.createCollection("system.profile",{capped:true, size: 1000000}) { "ok" : 1 } > db.system.profile.stats() { "ns" : "test.system.profile", "count" : 0, "size" : 0, "storageSize" : 1003520, "numExtents" : 1, "nindexes" : 0, "lastExtentSize" : 1003520, "paddingFactor" : 1, "systemFlags" : 0, "userFlags" : 0, "totalIndexSize" : 0, "indexSizes" : { }, "capped" : true, "max" : 2147483647, "ok" : 1 }关于capped Collections的介绍,请参考:http://blog.csdn.net/zhu_tianwei/article/details/44422995
三、查询分析器—dex
mongodb索引和查询分析器dex,是一种MongoDB的性能调整工具,比较MongoDB的日志文件和索引条目并给出索引建议。目前,必须提供一个连接数据库的URI。dex只建议完整的索引,而不是部分索引。不支持Windows平台。dex在运行过程中主要会进行下面三个步骤:
1.解析query
2.通过已存在的索引对当前query进行判断
3.如果发现索引不当,就推荐合适的索引。
第一步:解析query
Dex会对查询query进行解析,分成下面几大类
EQUIV – 普通按数值进行的查询,比如:{a: 1}
SORT – sort操作,比如: .sort({a: 1})
RANGE – 范围查询,比如:Specifically: ‘$ne’, ‘$gt’, ‘$lt’, ‘$gte’, ‘$lte’, ‘$in’, ‘$nin’, ‘$all’, ‘$not’
UNSUPPORTED
组合式查询,比如:$and, $or, $nor
除了RANGE之外的嵌套查询
第二步:判断当前索引情况
有两个标准来找出查询所需的索引。
Coverage (none, partial, full) - Coverage表示索引的情况,有括号中的三个值。none表示完全无索引覆盖。full表示query中的字段都能找到索引。partial表示none和full之间的情况。
Order (ideal or not) - Order是用于判断索引的顺序是否理想。理想的索引顺序应该是: Equivalence ○ Sort ○ Range 值得注意的是,对地理位置索引只会进行分析,但是不会提出改进建议。
第三步:推荐合适的索引
通过上面两步,我们能够对一个查询可能使用索引的情况有一个了解。Dex会生成一个此查询的最佳索引。如果这个索引不存在,并且查询情况不包括上面提到的UNSUPPORTED,那么Dex就会做出相应的索引优化建议。
具体使用参考:http://www.ttlsa.com/mongodb/mongodb-index-and-query-analyzer-tools-dex/
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇: JAVA常见错误处理方法
- 下一篇: Java常见内存溢出异常分析