mongodb系列(一)mongoose find普通查詢與aggregate聚合查詢的 簡單效能對比
阿新 • • 發佈:2020-11-04
背景
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