• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    MongoDB数据库查询性能提高40倍的经历分享

    前言

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

    背景说明

    1、数据库:MongoDB

    2、数据集:

    3、业务场景:求平均数

    进化过程

    在这里使用Python演示

    最直接想到的方法

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

    from pymongo import MongoClient
    # 连接数据库
    db = MongoClient('mongodb://127.0.0.1:27017')['my_db']
    
    # 简化的查询数据集A的条件
    filter = {...}
    # 查询Collection A
    a_cursor = db.a.find(_filter)
    a_docs = [x for x in a_cursor]
    
    # 变量的初始定义
    count = 0
    total = 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'])
    
    # 查询B
    b_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_size
    b_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性能优化的相关问题
    • MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划
    • MongoDB查询性能优化验证及验证
    • MongoDB性能优化及监控
    • 提升MongoDB性能的方法
    上一篇:Ubuntu下安装mongodb 3.4的详细过程
    下一篇:利用mongodb查询某坐标是否在规定多边形区域内的方法
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

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