优化一个简单的例子mongodb
这部分主要讲解如何优化MongoDB的性能。shell
让咱们举个具体示例。假使咱们的任务是现实blog的首页-咱们但愿现实最近发布的10条posts。ts为时间字段。数据库
语句以下数组
articles = db.posts.find().sort({ts:-1}); // get blog posts in reverse time orderfor (var i=0; i< 10; i++) { print(articles[i].getSummary());} 优化 #1: 建立索引服务器
第一个优化就是要在ts上建立索引,用来快速排序。网络
db.posts.ensureIndex({ts:1});app
使用索引,数据库就能够基于索引信息排序,不会直接查看每一个document。这样作更快。
ide
优化#2: 限定结果工具
MongoDB游标返回一组document,咱们叫这个为chunks。post
这chunk可能包含超过10个对象。额外的对象对于咱们的需求是浪费,
浪费了网络带宽和应用服务器以及数据库的资源。
咱们知道想要结果的个数,那么就不须要全部的结果。咱们能够使用limit()方法
articles = db.posts.find().sort({ts:-1}).limit(10); // 最多10条
如今,咱们从客户端返回了10条。
优化 #3: 查询相关的字段
post对象很是大, 如post文本和评论数组。 比较好的方式是只查询咱们要用到的字段。
articles = db.posts.find({}, {ts:1,title:1,author:1,abstract:1}).sort({ts:-1}).limit(10); articles.forEach( function(post) { print(post.getSummary()); } );
上面的getSummary()方法假使是能够得到find()方法返回的字段值
注意,若是你选择了要查询的字段,那么返回的就是部分对象。这个对象并不能直接进行更新。以下
a_post = db.posts.findOne({}, Post.summaryFields); a_post.x = 3; db.posts.save(a_post); // 错误,抛出异常使用 Profiler
MongoDB有一个数据库的 profiler,用来显示每一个操做的性能。
使用profiler你能够查看到哪些查询或者写入的速度比较慢。
举个例子,使用这些信息能够知道何时须要索引。详情查看 Database Profiler 。
Use count()优化语句
加速语句速度依赖于count(),建立一个索引,调用count()。
db.posts.ensureIndex({author:1}); db.posts.find({author:"george"}).count(); 增量操做Increment Operations
MongoDB 支持简单对象字段的增量操做;
基本上来讲, 这个操做就是 在服务器document中增量一个字段"。
这个要比"获取一个document,更新这个字段而且在保存会服务器"这个方法快不少,
而且对于实时的计数器更为有用。详情请看 Updates 。
固定大小的collection。
MongoDB提供了一个特殊的collection,它提早分配好了存储空间。
保存的项都是固定顺序的,而且没有索引。并且写入和读取是很是高速的。
存储是为了保存日志文件所设置的。详情查看 Capped Collections
服务端代码执行Server Side Code Execution
也许有的时候为了高性能,避免客户端和服务端来回通讯,须要直接在服务端执行代码。
这部分查看 Server-Side Processing 。
Explain工具
要想查看查询语句的详细性能信息,最好的方法就是使用explain方法。
返回的结果就是整个查询执行的一些信息。
当使用shell的时候,能够调用cursor的explain() 方法。
db.collection.find(query).explain();
返回的信息以下
{"cursor" : "BasicCursor", "indexBounds" : [ ], "nscanned" : 57594, "nscannedObjects" : 57594, "nYields" : 2 , "n" : 3 , "millis" : 108, "indexOnly" : false}
nscanned - 扫描的数据条数。这个数据多是对象也多是索引的键。 若是"覆盖索引(covered index)"被调用了,nscanned 要高于nscannedObjects. nscannedObjects - 扫描对象的数。 nYields - 查询所产生的锁的个数。 indexOnly - 是否使用了covered index。
Hint
虽然MongoDB查询优化器通常工做的很不错,可是也能够使用hints来强迫MongoDB使用一个指定的索引。
这种方法某些情形下会提高性能。 一个有索引的collection而且执行一个多字段的查询(一些字段已经索引了)。
传入一个指定的索引,强迫查询进行使用。
db.collection.find({user:u, foo:d}).hint({user:1});
|
肯定建立了索引。 上面的例子,首先你肯定索引已经建立了。请使用ensureIndex()建立索引。 |
其余的例子,有个在 {a:1, b:1} 上的索引,名称为"a_1_b_1":
db.collection.find({a:4,b:5,c:6}).hint({a:1,b:1}); db.collection.find({a:4,b:5,c:6}).hint("a_1_b_1");
强迫查询不适用索引, (作一个表的扫描), 使用:
> db.collection.find().hint({$natural:1})