您的位置:首页 > 数据库 > Mongodb

MongoDB 索引优化

2016-09-27 17:36 381 查看
索引是用来加快查询速度的,事物都有双面性的,同时在每次插入、更新和删除操作时都会产生额外的开销。索引有时并不能解决查询慢的问题,一般来说,返回集合中一半以上的结果,全表扫描要比查询索引更高效些。创建太多索引,会导致插入非常慢,同时还会占用很大空间。可以通过一些工具来分析查询的效率来进一步优化索引。

一、MongoDB自带工具explain

使用explain命令返回查询使用的索引情况,耗时,扫描文档数等等统计信息。 

[plain] view
plain copy

 print?





> 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 

[plain] view
plain copy

 print?





>db.setProfilingLevel(1,100)   

{ "was" : 0, "slowms" : 100, "ok" : 1 }   

>db.setProfilingLevel(0)   

3.查询profiling记录 

MongoDB Profile 记录是直接存在系统 db 里的,记录位置system.profile 。 

[plain] view
plain copy

 print?





> 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

[plain] view
plain copy

 print?





> 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的记录 

[plain] view
plain copy

 print?





> 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就会做出相应的索引优化建议。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: