MongoDB 優(yōu)化博客分類:
MongoDB應(yīng)用服務(wù)器Blog網(wǎng)絡(luò)應(yīng)用MongoDB優(yōu)化一個(gè)簡(jiǎn)單的例子
這部分主要講解如何優(yōu)化MongoDB的性能。
讓我們舉個(gè)具體示例。假使我們的任務(wù)是現(xiàn)實(shí)blog的首頁-我們希望現(xiàn)實(shí)最近發(fā)布的10條posts。ts為時(shí)間字段。
語句如下
articles = db.posts.find().sort({ts:-1}); // get blog posts in reverse time orderfor (var i=0; i< 10; i++) { print(articles[i].getSummary());}
優(yōu)化 #1: 創(chuàng)建索引
第一個(gè)優(yōu)化就是要在ts上創(chuàng)建索引,用來快速排序。
db.posts.ensureIndex({ts:1});
使用索引,數(shù)據(jù)庫就可以基于索引信息排序,不會(huì)直接查看每個(gè)document。這樣做更快。
優(yōu)化#2: 限定結(jié)果
MongoDB游標(biāo)返回一組document,我們叫這個(gè)為chunks。
這chunk可能包含超過10個(gè)對(duì)象。額外的對(duì)象對(duì)于我們的需求是浪費(fèi),
浪費(fèi)了網(wǎng)絡(luò)帶寬和應(yīng)用服務(wù)器以及數(shù)據(jù)庫的資源。
我們知道想要結(jié)果的個(gè)數(shù),那么就不需要所有的結(jié)果。我們可以使用limit()方法
articles = db.posts.find().sort({ts:-1}).limit(10); // 最多10條
現(xiàn)在,我們從客戶端返回了10條。
優(yōu)化 #3: 查詢相關(guān)的字段
post對(duì)象非常大, 如post文本和評(píng)論數(shù)組。 比較好的方式是只查詢我們要用到的字段。
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()方法返回的字段值
注意,如果你選擇了要查詢的字段,那么返回的就是部分對(duì)象。這個(gè)對(duì)象并不能直接進(jìn)行更新。如下
a_post = db.posts.findOne({}, Post.summaryFields);a_post.x = 3;db.posts.save(a_post); // 錯(cuò)誤,拋出異常
使用 Profiler
MongoDB有一個(gè)數(shù)據(jù)庫的 profiler,用來顯示每個(gè)操作的性能。
使用profiler你可以查看到哪些查詢或者寫入的速度比較慢。
舉個(gè)例子,使用這些信息可以知道什么時(shí)候需要索引。詳情查看
Database Profiler 。
Use count()優(yōu)化語句
加速語句速度依賴于count(),創(chuàng)建一個(gè)索引,調(diào)用count()。
db.posts.ensureIndex({author:1});db.posts.find({author:"george"}).count();
增量操作Increment Operations
MongoDB 支持簡(jiǎn)單對(duì)象字段的增量操作;
基本上來說, 這個(gè)操作就是 在服務(wù)器document中增量一個(gè)字段"。
這個(gè)要比"獲取一個(gè)document,更新這個(gè)字段并且在保存會(huì)服務(wù)器"這個(gè)方法快很多,
并且對(duì)于實(shí)時(shí)的計(jì)數(shù)器更為有用。詳情請(qǐng)看
Updates 。
固定大小的collection。
MongoDB提供了一個(gè)特殊的collection,它提前分配好了存儲(chǔ)空間。
保存的項(xiàng)都是固定順序的,并且沒有索引。而且寫入和讀取是非常高速的。
存儲(chǔ)是為了保存日志文件所設(shè)置的。詳情查看
Capped Collections服務(wù)端代碼執(zhí)行Server Side Code Execution
也許有的時(shí)候?yàn)榱烁咝阅?,避免客戶端和服?wù)端來回通信,需要直接在服務(wù)端執(zhí)行代碼。
這部分查看
Server-Side Processing 。
Explain工具
要想查看查詢語句的詳細(xì)性能信息,最好的方法就是使用explain方法。
返回的結(jié)果就是整個(gè)查詢執(zhí)行的一些信息。
當(dāng)使用shell的時(shí)候,可以調(diào)用cursor的explain() 方法。
db.collection.find(query).explain();
返回的信息如下
{"cursor" : "BasicCursor", "indexBounds" : [ ], "nscanned" : 57594, "nscannedObjects" : 57594, "nYields" : 2 , "n" : 3 , "millis" : 108, "indexOnly" : false}
現(xiàn)實(shí)結(jié)果可以得知cursor的類型,DB掃描的數(shù)據(jù)數(shù),返回的數(shù)據(jù)數(shù),還有執(zhí)行的毫秒數(shù)。
nscanned - 掃描的數(shù)據(jù)條數(shù)。這個(gè)數(shù)據(jù)可能是對(duì)象也可能是索引的鍵。
如果"覆蓋索引(covered index)"被調(diào)用了,nscanned 要高于nscannedObjects.
nscannedObjects - 掃描對(duì)象的數(shù)。
nYields - 查詢所產(chǎn)生的鎖的個(gè)數(shù)。
indexOnly - 是否使用了covered index。
Hint
雖然MongoDB查詢優(yōu)化器一般工作的很不錯(cuò),但是也可以使用hints來強(qiáng)迫MongoDB使用一個(gè)指定的索引。
這種方法某些情形下會(huì)提升性能。 一個(gè)有索引的collection并且執(zhí)行一個(gè)多字段的查詢(一些字段已經(jīng)索引了)。
傳入一個(gè)指定的索引,強(qiáng)迫查詢進(jìn)行使用。
db.collection.find({user:u, foo:d}).hint({user:1});
確定創(chuàng)建了索引。
上面的例子,首先你確定索引已經(jīng)創(chuàng)建了。請(qǐng)使用ensureIndex()創(chuàng)建索引。
其他的例子,有個(gè)在 {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");
強(qiáng)迫查詢不適用索引, (做一個(gè)表的掃描), 使用:
> db.collection.find().hint({$natural:1})