侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

MongoDB数据库查询性能提高40倍的经历分享

数据库  /  管理员 发布于 6年前   163

前言

数据库性能对软件整体性能有着至关重要的影响,本文给大家分享了一次MongoDB数据库查询性能提高40倍的经历,感兴趣的朋友们可以参考学习。

背景说明

1、数据库:MongoDB

2、数据集:

  • A:字段数不定,这里主要用到的两个UID和Date
  • B:三个字段,UID、Date、Actions。其中Actions字段是包含260元素JSON数组,每个JSON对象有6个字段。共有数据800万条左右。

3、业务场景:求平均数

  • 通过组合条件从A数据表查询出(UID,Date)列表,最多可能包含数万条记录;
  • 然后用第1步的结果从B中查询出对应的数据
  • 用第2步结果去Actions的某个固定位置的元素的进行计算

进化过程

在这里使用Python演示

最直接想到的方法

根据上面的业务场景描述,最容易想到的解决方法就是

from pymongo import MongoClient# 连接数据库db = MongoClient('mongodb://127.0.0.1:27017')['my_db']# 简化的查询数据集A的条件filter = {...}# 查询Collection Aa_cursor = db.a.find(_filter)a_docs = [x for x in a_cursor]# 变量的初始定义count = 0total = 0# 加入需要用到的元素为第21个index = 20# 查询Collection B,同时做累加for a_doc in a _docs: b_doc = db.b.find_one({'uid':a_doc['uid'], 'date': a_doc['date']}) # 只有能查到相应的结果时,才可以 if b_doc is not None: total += b_doc['actions'][20]['number'] count += 1 # 求平均数 if count > 0 : avg = total/count

实现难度当然是最低的,可是整个任务在第一步只有1万条左右的返回时,消耗的时间竟然达到了惊人38秒。当然这是已经加了索引的结果,否则可能都无法得到结果了。

减少查询次数

瓶颈显而易见,在循环中查询Collection B,增加了网络开销,自然也就增加时间,如果一次查询出所有结果,自然会大大提高效率。也就是说,我要把第一步的结果作为条件一次性传递,做一个$in操作。可是怎么才能做到呢?如果在uid和date上分别做$in操作,那么返回的结果就会是二者单独做$操作的合集,很显然这和要求是不符的。

经过上面的分析,似乎进入了死胡同。其实答案也基本显现了,需要有一个字段可以满足上面的要求,那么这个字段就是uid和date的合体,就命名为uid_date。uid_date是一个新字段,在B中并不存在,在使用之前需要将数据库现有的数据做一下处理。

处理完毕改造程序:

# 下面的只体现和本次修改相关的内容uid_date_list = []for a_doc in a_docs: uid_date_list.append(a_doc['uid'] + '_' + a_doc['date'])# 查询Bb_cursor = db.b.find({'uid_date':{'$in':uid_date_list}})# 下面就是取出结果,求平均数...

这一番改造颇费时间,主要是前期的数据处理。代码改造完毕,执行下看看吧。

可是,可是…… 45秒

我做错了什么?!

增加返回记录数

我还是坚信上面的优化思路是对的,现在看看数据库能给一些什么线索吧。

登录到数据库服务器,找到MongoDB的日志/data/mongodb/logs/mongod.log。仔细查找,发现在查询数据集B时有很多getMore命令。这就奇怪了,我是一次性查询,为什么还有getMore。

赶紧查下官方的文档,然后发现了下面的内容:


batcSize参数指定了每次返回的个数,默认的101个。那看来这个应该是问题所在。找下pymongo的文档,也可以设置这个参数,那就设个大的吧10000。

再次改造程序如下:

# 增加batch_sizeb_cursor = db.b.find({'uid_date':{'$in': uid_date_list}}, batch_size=10000)

这次总该可以了。

嗯,好了一些,降到了20秒左右。可是,这离1秒只能还差距20倍呢。

返回值减负

当日不能放弃,继续通过日志查找线索,发现还是有很多getMore。通过各方查找,发现mongodb每次最多返回16M的记录,通过getMore日志的比对,发现的确如此。由于B中每条记录的过去庞大,每次只能几百条记录,因此要一次多返回,那就必须要减少每次返回的记录数。因为在计算时,只用了特定索引位置上的数据,所以只返回该条记录就可以了。

最后的代码就不再写了,具体可以参考官方文档的实例。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。


  • 上一条:
    记一次MongoDB性能问题(从MySQL迁移到MongoDB)
    下一条:
    MongoDB数据库中索引(index)详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客