mongoDB 性能优化:如何使用普通查询语句替代 aggregate 操作?

来源:互联网 发布:ubuntu 16 rc.local 编辑:程序博客网 时间:2024/04/28 07:11
我们知道,mongo 里的普通查询语句是没有分组查询功能的,如果要实现类似于关系型数据库 SQL 里的 group by 操作就要用 aggregate。遗憾的是副本集中,aggregate 操作是在主库执行(比如笔者的 3.0.3 就是这样的,据说 mongo 新版本会改善这一状况 - 将 aggregate 操作放到从库执行),这对于读写分离的副本集是不合理的,大并发时的大量慢查询操作很容易将主库给拖死。
要想提高主库性能,优化 aggregate 慢查询是一个不错的办法,但是如果能将 aggregate 换成普通查询语句进而去从库执行(实现读写分离)也不失为一个不错的优化方案。本文将以一个实战例子详解如何使用普通查询语句替代 aggregate 操作,本文示例代码均采用 go 语言实现。
database.C(col.name).Pipe([]bson.M{{"$match": find},{"$group": bson.M{"_id": "$merId"}},{"$group": bson.M{"_id": "null", "total": bson.M{"$sum": 1}}},}).One(&total)

代码解析:find 对象是一个用于存放查询条件的 BSON map(类似于 SQL 里的 where 从句),total 是一个自定义的用于存放返回结果的结构体(类似于 JDK JDBC API 里的 ResultSet)。上述查询使用了两层 group,第一层按 merId 进行分组,第二层对第一层分组后的 merId 个数进行统计。
理解其要做的事情之后,我们可以还是按 find 的条件进行查询,调用查询结果(是一个 v2.Query 对象)的 Distinct 函数对 merId 进行分组 - 这一步实现了上述语句的第一层 group;merId 分组后我们在对这个分组执行查看长度的操作,实现上述 aggregate 中的第二层分组。go 语言示例代码如下:
var itotal int = 0var res []stringerr := database.C(col.name).Find(find).Distinct("merId", &res)if err != nil {log.Errorf("fail: %s", err)}itotal = len(res)total.Value = itotal

这段代码实现的功能和上述 aggregate 实现的功能是一样的,但它是在从库执行。美中不足的是要把所有符合条件的 merId 都从数据库拉到应用,之后由应用计算其长度,因为 Distinct 返回的结果是一个 error 接口,不能够计算 merId 集合的长度,但牺牲的这点应用内存和应用数据库带宽能换来 mongo 副本集主从库的读写分离,还是值得的。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机点击不明链接怎么办 华为手机wifi慢怎么办 浏览器打不开显示内存不足怎么办 华为电脑黑屏了怎么办 华为电脑关不了怎么办 xp系统不能上网怎么办 华为手机激活码怎么办 华为系统删了怎么办 来电响铃时间短怎么办 华为p10刚开机怎么办 盒子支付不到账怎么办 小米5x录完音乱怎么办 华为返回键失灵怎么办 手机退出键失灵怎么办 公司座机被骚扰怎么办 手机号被拦截了怎么办 收不到话费短信怎么办 移动信息收不到怎么办 电话被拦截了怎么办 华为屏幕有广告怎么办 手机屏幕突然出广告怎么办? 电脑中病毒网络怎么办 手机被短信轰炸怎么办 手机桌面变暗了怎么办 oppo音乐不能用怎么办 华为p7更新不了怎么办 短信文件夹没了怎么办 手机安全拦截了怎么办 遇到信号屏蔽器怎么办 电脑老是叫更新怎么办 安卓 启动器停止怎么办 忘记手机pin密码怎么办 华为y635cl00太慢怎么办 ipad玩王者卡怎么办 手机天气不更新怎么办 手机权限被拒绝怎么办 小米平板相册打不开怎么办 小米平板打不开了怎么办 oppo照片消失了怎么办 被别人标记电话怎么办 点了病毒链接怎么办