MongoDB的性能优化

来源:互联网 发布:教师网络信息管理平台 编辑:程序博客网 时间:2024/05/16 09:29

      说到数据库方面的优化,我们首先想到的是利用索引技术,mongoDB作为数据库的一种,利用索引来提高查询效率同样适用。下面就我在mongoDB的日常工作中经常使用到的性能优化谈谈自己的理解。

一:利用explain执行计划来查看系统执行过程

     MongoDB本身提供了一个explain()命令来获取系统执行查询的处理过程,如下图:


重要字段说明如下:

* cursor:返回的游标类型,一般分为BasicCursor(系统默认游标)和BtreeCursor(基于树的游标)。

*nscanned:被扫描的文档数量。

*n:返回的文档数量。

*millis:执行查询所消耗的时间,单位为毫秒。

*indexOnly:是否使用索引。

*indexBound:所使用的索引列表。

下面我们建立索引,来看看explain的执行过程:


      上图中可以看出,建立索引后游标类型变成了基于树状的Btree结构游标,搜索速度快,从而大大提高了执行查询效率。

       索引可以提高查询性能,但有一点需要注意的是,索引并不是越多越好,如果建立过多,系统性能反而会下降。因为每当你建立一个索引时,系统都会建立一个索引表,用于检索指定的列,下次当你对已建立的索引列进行插入或者修改时,数据库都会对原来的索引表进行重新排序,在这过程中会非常消耗性能。


二:优化器Profiler解析

        Mongodb本身带有一种profiler机制,可以方便地记录所有耗时的操作,以便于调优。

开启profiler功能有两种方法:

第一种就是直接在启动参数里面进行设置,就在启动mongodb时候添加-profile=“级别“:

 mongod --profile=1 --slowms=15

第二种就是在客户端执行“db.setProfilingLevel(级别,slowms)”命令:

 db.setProfilingLevel(0,20)

这里的“级别”分为:0(不开启),1(记录慢命令),2(记录所有命令)。slowms参数代表慢操作记录的开始时间,默认为100ms。

        需要注意的是,慢操作记录的开始时间slowms会应用到整个mongod实例中,当你改变了记录开始时间,你会改变整个数据库实例状态。这一点非常重要,官网中有特别指出:


当你开启优化器profiler时,系统会自动在数据库中创建一个system.profile集合,这个集合会默认记录所有的慢操作日志。

查询集合结果如下:

>db.system.profile.find()       { "ts" : ISODate("2016-06-16T19:45:10.359Z"), "info" : "query test.system.profile reslen:36 nscanned:0  \nquery: {}  nreturned:0 bytes:20", "millis" : 0 }      { "ts" : ISODate("2016-06-16T19:45:13.562Z"), "info" : "query test.$cmd ntoreturn:1 command: { count: \"system.profile\", query: {}, fields: {} } reslen:64 bytes:48", "millis" : 0 }      { "ts" : ISODate("2016-06-16T19:45:13.562Z"), "info" : "query test.system.profile ntoreturn:5 reslen:36 nscanned:2  \nquery: { query: { millis: { $gt: 0.0 } }, orderby: { $natural: -1.0 } }  nreturned:0 bytes:20", "millis" : 0 }      { "ts" : ISODate("2016-06-16T19:45:17.171Z"), "info" : "query test.emp reslen:261 nscanned:5  \nquery: {}  nreturned:5 bytes:245", "millis" : 0 }
主要参数说明如下:

ts:该命令执行的时间。

info:本命令的详细信息。

reslen:返回结果集的大小。

nscanned:本次查询扫描的记录数。

nretured:本次查询时间返回的结果集。

millis:该命令执行的耗时。单位为毫秒


profile分析数据查询示例:

//1.执行时间大于5毫秒的操作信息:>db.system.profile.find( { millis : { $gt : 5 } } ).pretty()//2.某一时间段的操作执行信息:>db.system.profile.find(                       {                        ts : {                              $gt : new ISODate("2016-06-17T03:00:00Z") ,                              $lt : new ISODate("2016-06-17T03:40:00Z")                             }                       }                      ).pretty()//3.在某一时间段,某一用户执行信息并对每一次操作执行所消耗的时间进行排序:>db.system.profile.find(                       {                         ts : {                               $gt : new ISODate("2016-06-17T03:00:00Z") ,                               $lt : new ISODate("2016-06-17T03:40:00Z")                              }                       },                       { user : 0 }                      ).sort( { millis : -1 } )
       当开启优化器profiler,其实只会对系统性能产生较小的效果。system.profile是一个默认大小为1M的capped collection集合,这样大小的集合通常可以存储数千的profile文档数据,但是有一些应用程序每执行一次操作,可能会产生更多或者更少的分析数据。


如何改变system.profile集合的大小?
例如,你需要创建一个400000bytes的system.profile集合,在mongo脚本执行以下命令:

//1.关闭优化器>db.setProfilingLevel(0)//2.删除system.profile>db.system.profile.drop()//3.创建一个新的system.profile集合>db.createCollection( "system.profile", { capped: true, size:4000000 } )//4.重启优化器>db.setProfilingLevel(1)


三:性能优化总结

 方法1:采用Index索引技术。如前面所述,索引并不是越多越好,那什么情况下建立索引最好呢?当你数据库的总记录数远大于你需要返回结果的记录,并且读请求较多的时候,创建索引是一个非常好的选择。

方法2:只查询你需要的部分字段,不要查询所有字段。这种方法很好理解。比如说一个银行的客户信息存储非常大,但我们只需要查询出所有客户姓名字段即可,这样比在数据库调取出客户所有信息显然快很多。

方法3:利用优化器Profiler。如前面所述,开启profile功能会影响系统效率的,但影响效果较小。因为它采用的是system.profile集合来记录,这个集合是一个Capped Collction,存储查询效率高。

方法4:直接使用Capped Collction。这个集合其实是一个具有固定大小,默认基于insert次序排序,并且采用FIFO算法的集合(详细解释会在后面文章中指出),读写效率比普通的Collection高。

方法5:采用Server Side Code Exeution。这个方法就非常类似于sql数据库中存储过程,将一些常用的sql功能进行封装,需要时直接调用,会大大减少网络传输的开销。

另外如使用hint强制使用索引,以及限制limit返回的结果条数这些,都是可选的优化方法。

0 0
原创粉丝点击