背景
mongodb 3.4,使用默認的配置(沒有調整內存限制或其他性能配置),數據庫有90萬+條數據

開始實驗
以下分別使用 find 查詢 和 aggregate 聚合查詢
以下為dao層(server/dao/cmsResourceDao.js),基於mongoose查詢mongodb
-
getModel(){
-
return mongoose.model(this.model_name); //model_name 為collection名稱
-
}
-
-
/***
-
* 使用find 查詢,並且是分頁查詢
-
* @param limit_param 條件
-
* @param page_index 數據頁碼起始下標
-
* @param page_size 數據每頁數量
-
* @param sort 排序條件
-
* @returns {Promise.<{rows: *, total_count: *}>}
-
*/
-
async listPage(limit_param,page_index,page_size,sort){
-
let rows;
-
if(sort != null){
-
rows = await this.getModel().where(limit_param).skip(Number(page_index)).limit(Number(page_size)).sort(sort).exec();
-
} else{
-
rows = await this.getModel().where(limit_param).skip(Number(page_index)).limit(Number(page_size)).exec();
-
}
-
return {rows};
-
}
-
-
/***
-
* 使用aggregate聚合 查詢,並且是分頁查詢
-
* @param limit_param 條件
-
* @param page_index 數據頁碼起始下標
-
* @param page_size 數據每頁數量
-
* @param sort 排序條件
-
* @returns {Promise.<{rows: *, total_count: *}>}
-
*/
-
async listAggregatePage(limit_param,page_index,page_size,sort){
-
-
let aggregate_limit = [{$match:limit_param},
-
{ $skip:Number(page_index)},
-
{ $limit:Number(page_size)}];
-
-
if(sort != null)aggregate_limit.push({$sort:sort});
-
-
let rows = await this.getModel().aggregate(aggregate_limit);
-
return {rows};
-
}
1.find查詢和aggregate查詢(不使用sort排序)
以下為使用find查詢50000條數據返回:
-
async list(ctx,next){
-
-
console.log('list!!!');
-
let type = ctx.request.query.type;
-
let page_index = ctx.request.query.page_index;
-
let page_size = ctx.request.query.page_size;
-
-
let where = {};
-
if(type != null)where.type = type;
-
-
let start_time = new Date().getTime();
-
let result = await dao.listPage(where,page_index,page_size);
-
// let result = await dao.listAggregatePage(where,page_index,page_size); //使用聚合查詢方式
-
let end_time = new Date().getTime();
-
console.log('查詢時間:');
-
console.log(end_time - start_time);
-
ctx.body = {
-
data : result,
-
time : new Date().getTime() - start_time
-
}
-
}
打印的時間是: 8504ms
使用aggregate查詢50000條數據返回:
-
async list(ctx,next){
-
-
console.log('list!!!');
-
let type = ctx.request.query.type;
-
let page_index = ctx.request.query.page_index;
-
let page_size = ctx.request.query.page_size;
-
-
let where = {};
-
if(type != null)where.type = type;
-
-
let start_time = new Date().getTime();
-
// let result = await dao.listPage(where,page_index,page_size);
-
let result = await dao.listAggregatePage(where,page_index,page_size); //使用聚合查詢方式
-
let end_time = new Date().getTime();
-
console.log('查詢時間:');
-
console.log(end_time - start_time);
-
ctx.body = {
-
data : result,
-
time : new Date().getTime() - start_time
-
}
-
}
打印的時間是: 2241ms
2.find查詢和aggregate查詢(使用sort排序)
使用sort排序挑戰性能極限
在剛才使用find查詢,添加sort條件
let result = await dao.listPage(where,page_index,page_size,{updated_at:-1});
結果控制台報出,內存超出限制(最大值為 33554432 bytes 折合為 32mb左右 ):
service error { MongoError: Executor error during find command: OperationFailed: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.
使用aggregate查詢,添加sort條件
let result = await dao.listAggregatePage(where,page_index,page_size,{updated_at:-1}); //使用聚合查詢方式
打印的時間是: 2298ms
那么aggregate查詢的內存最大值究竟有多少呢?再玩大的,這次查詢10萬條
service error { MongoError: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in.
由此可見 aggregate對排序也是有內存限制的(最大值為104857600 bytes折合為100mb左右)
總結
從查詢的速度看,aggregate效率更勝一籌。
從內存限制看,aggregate比find更高一點。
從上述實驗中,aggregate 好像比 find 查詢 更勝一籌,但並不意味着 aggregate就是最好的,初步判斷這是由於aggregate更消耗內存換取查詢的速度。下一集,再深層次挖掘兩者區別
PS: 源碼已提交到github
