1. 程式人生 > >解決mongodb查詢慢的問題

解決mongodb查詢慢的問題

修改器 lis arp dcl 查詢條件 集合 ODB 總數 order

最近項目上一直在用mongodb作為數據庫,mongodb有他的優勢,文檔型類json格式存儲數據,修改起來比傳統的關系型數據庫更方便,但是最近在用mongodb出現了查詢緩慢的問題,我用命令行查詢,顯示速度非常快,而且也添加了索引,2萬條數據只需要十幾毫秒,但是用代碼實現卻需要好幾秒,我調試了代碼發現代碼生成的查詢語句跟我在命令行的查詢語句是一樣的,我當時就很納悶。

我當時的代碼是這樣寫的:

var list = collection.FindAs<AdClick>(query).SetSortOrder(s).toList();

這是很正常的一行代碼,根據查詢條件,按照排序返回List集合,當我去掉tolist之後,速度就秒查了,然後我看到返回的類型是mongoCursor。這裏我要介紹一下MongoCursor,他是mongo的遊標,他其實並沒有真正的查詢到結果,相當於懶加載,

在調用find時,MongoDB shell並不立即查詢數據庫,而是在等待真正開始獲取數據時才發送查詢。(類似Linq中IQueryable),你可以通過遊標來對最終結果進行控制。比如限制結果數量,略過某一部分,根據任意鍵按任意順序的組合對結果進行各種排序等。當時當你調用ToList()的時候,他就會把查詢數據全部加載到內存,如果查詢的數據多,這個過程那個就會很慢,所以真正慢的原因,就是ToList(),知道了慢的原因修改器起來就很好改了。


但是修改了這個又發現了另外一個問題,那就是Mongodb加查詢條件的count()也會很慢,因為做統計需要得到總數,直接不加查詢條件直接調用Count()比加了查詢條件調用count()快,因為mongodb的查詢是根據索引來的,如果你查詢條件越多,沒有命中查詢條件的索引,就會全文搜索,所以就會很慢,所以使用count()函數的時候,盡量不加查詢條件,但顯然是不現實的,因為查詢條件會必然很多。 後來在網上看到一個解決方案就是用MongoCursor.Size()方法,果然速度快了很多,不知道原因,沒有仔細研究。



還有一個問題,就是mongo的分頁問題,你會發現,開始幾頁會很快,越到後面,分頁越慢,這是mongo會把查詢結果加載到內存,由於內存的限制,越到後面越慢,有什麽解決方案呢?


db.test.sort({"amount":1}).skip(100000).limit(10) //183ms
db.test.find({amount:{$gt:2399927}}).sort({"amount":1}).limit(10) //53ms
根據查詢條件加載分頁,只查詢10條數據加載到內存,skip分頁貌似很影響效率,不要輕易使用Skip來做查詢,否則數據量大了就會導致性能急劇下降,這是因為Skip是一條一條的數過來的,多了自然就慢了。

解決mongodb查詢慢的問題