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就会做出相应的索引优化建议。
一、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就会做出相应的索引优化建议。
相关文章推荐
- MongoDB-性能优化之索引
- MongoDB组合索引的优化
- 精通MongoDB-索引与查询优化
- MongoDB学习笔记(8)--索引及优化索引
- MongoDB优化,建立索引实例及索引机制原理讲解
- mongodb 索引优化再优化【前缀大致相同】
- mongodb索引优化的方法
- 第五章 MongoDb索引优化 5.1
- MongoDB范围查询的索引优化
- 第五章 MongoDb索引优化 5.2
- 10gen工程师谈MongoDB组合索引的优化
- MongoDB 索引数据类型优化,节省60%内存
- 10gen工程师谈MongoDB组合索引的优化
- 使用NOSQL的MongoDB建立索引时需要注意的几点建议和Explain优化分析
- 第五章 MongoDb索引优化 5.3
- MongoDB的索引与查询优化
- Mongodb 3 查询优化(语句优化、建索引)
- mongodb 优化索引心得
- 使用NOSQL的MongoDB时建立索引需要注意的几点建议和Explain优化分析
- 第五章 MongoDb索引优化 5.4