背景
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
https://github.com/rcjjian/big_data_lab