眾所周知, mongo db的count查詢是相當(dāng)慢的, 但是count的查詢又是非常常見的作用.
筆者最近就有一項需要,需要在200萬條數(shù)據(jù)中執(zhí)行count查詢,并且使用MongoTemplate.count()查詢,結(jié)果查詢結(jié)果很慢.
那么如何解決這個問題呢? 筆者查詢了相關(guān)的資料. 采用了以下方案供大家參考.
首先,筆者在mongo shell中執(zhí)行db.collection.find({}).count()不用1s的時間就出來結(jié)果, 因此, 筆者首先想到的是能不能再java mongo中直接執(zhí)行mongo shell的命令, 很不幸, 筆者使用的是4.4版本的mongodb, 不在支持db.eval()操作. 因此只能選擇其他方法
相關(guān)資料可以參考這個:
https://stackoverflow.com/questions/16239592/raw-javascript-mongodb-queries-using-db-eval-in-java
https://docs.mongodb.com/manual/reference/method/db.eval/
經(jīng)過網(wǎng)上查詢和官方文檔提示, mongodb支持以下的count查詢
- db.collection.count()
- db.collection.countDocuments()
- db.collection.estimatedDocumentCount()
這三個方法對比著看,會有更深的認識
方法對比
count
- 采用
metadata來返回數(shù)據(jù)總量
countDocuments
- 未采用
metadata - 通過
aggregation來實時計算出數(shù)量
改語法封裝了下面的語句,來返回數(shù)量
db.collection.aggregate([
{$match: <query>},
{$group: {_id: null, n: {$sum: 1}}}
])
estimatedDocumentCount
說明
- 該方法返回一個collection中的所有documents的數(shù)量
- 該方法封裝了count命令
- 該方法采用了
metadata
使用
db.collection.estimatedDocument(<options>)
使用示例
綜合上述三個方法的對比. 在計算count的時候, 根據(jù)查詢條件的不同,可以采用不同的方法
- 如果沒有查詢條件,即查詢總量時,建議采用
estimatedDocumentCount方法 - 如果有查詢條件, 只能通過
countDocuments方法, 并且減以在查詢條件增加索引.
Java代碼片段示例
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.MongoTemplate;
long count = 0;
if (query.getQueryObject().isEmpty()) {
LOGGER.info("[Mongo] ==> 開始查詢總量");
long startTime = System.currentTimeMillis();
count = mongoTemplate.getCollection(tableName).estimatedDocumentCount();
LOGGER.info("[Mongo] ==> 結(jié)束查詢總量,耗時:{}ms", System.currentTimeMillis() - startTime);
} else {
LOGGER.info("[Mongo] ==> 開始條件查詢總量");
long startTime = System.currentTimeMillis();
count = mongoTemplate.count(query, tableName);
LOGGER.info("[Mongo] ==> 結(jié)束條件查詢總量,耗時:{}ms", System.currentTimeMillis() - startTime);
}