MongoDB 性能优化之索引优化

索引是用来加快查询速度的,事物都有双面性的,同时在每次插入、更新和删除操作时都会产生额外的开销。索引有时并不能解决查询慢的问题,一般来说,返回集合中一半以上的结果,全表扫描要比查询索引更高效些。创建太多索引,会导致插入非常慢,同时还会占用很大空间。可以通过一些工具来分析查询的效率来进一步优化索引。
一、MongoDB自带工具explain
使用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/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值