如何对10亿数据量级的mongoDB作高效的全表扫描
来源:互联网 发布:淘宝自拍照布灯 编辑:程序博客网 时间:2024/04/29 21:03
本文链接: http://quentinXXZ.iteye.com/blog/2149440
一、正常情况下,不应该有这种需求
首先,大家应该有个概念,标题中的这个问题,在大多情况下是一个伪命题,不应该被提出来。要知道,对于一般较大数据量的数据库,全表查询,这种操作一般情况下是不应该出现的,在做正常查询的时候,如果是范围查询,你至少应该要加上limit。
说一下,我的应用场景:用于全量建立搜索引擎的索引。这就是一种需要用到全表扫描的非一般情况。对于全表扫描的结果,我们没有排序要求。
二、情况说明
既然有如此大的数据量,那存储所占空间基本都是上T的了。所以肯定是使用了mongodb集群,而且配置了分片的分布式环境。
公司的服务器,性能比较好,应该是24核,96g内存的。所以读者们使用不同机器,测出来的用时,跟我这的结果可能不一定相符。
三、第一种方法,利用chunk信息作划分。
原理:我们知道,在分片环境下,mongodb使用chunk块来组织数据。同一个chunk块的数据肯定存在于同一个分片上。假设,我们以 “_id”作分片时所用的片键。Mongodb为了保证范围查找的效率,一定会将一定范围内的_id值的document方在同一个chunk中。而且通过mongodb自身提供的方法,我们可以很方便的获取,每一个chunk的中maxKey与minKey。[minKey,maxKey) 这个范围内的数据肯定在同一个chunk内,也并定在同一个分片中。
做法:1、先获取所有chunk信息,得到他们的maxKey与minKey。
2、多线程执行,将这些chunk信息,分发给这些执行线程。
3、各线程,根据当前的chunk与 maxKey与minKey信息,做范围查找。
4、最后将结果汇总。
这样做的好处在于:
1、每次对一个chunk做的范围查找,肯定是只在一个分片(意味着同一块硬盘)中进行的,不会分散到多个分片。这样很高效。
2、可以方便的利用多线程,提高效率。
这种方法我没试过,公司的前辈尝试过,据说,最终用时3小时以内。是最为理想的效果。
四、改用散列片键后的全表扫描方法
用上面的方法,有一个前题,就是分片策略采用的是mongodb默认的升序片键的方法。这样才保证,升序的_id,会按排序范围分布在chunk块中。这样这策略,存在一个明显的问题,就是会造成所以新增的doucument的写入肯定都会命中到具有当前最大_id的chunk上。造成写入的分发的不平衡。
前文中,说过,全表扫描,应该是一个正常情况下不被允许的情况。所以数据库策略的制定也不应该以考虑全表扫描的效率为优先,当前情况下,就应以写入效为优先考虑。公司正在使用的片键策略,是片键策略散列片键(hashed shard key),这样的话,写入请况会被很好地分发到多个分片上,但是不利用进行范围查找。上面用的全表扫描方法就没法再用了。
做法:1、获得全局的最大id maxID与全局的最小id minID。
2、设置一个stepSize ,比如5000。将[minID,maxID]按5000为一个chunk(我们定义的一个逻辑chunk)作切分,那么第一个块范围[minID,minID+5000),
3、各线程,根据分配到的chunk块的maxID与minID信息,做范围查找。
4、最后将结果汇总。
这样做法的问题:
1、对一个chunk进行查询,会命中多个分片进行查询,查询效率大幅降低。
2、 如果_id分布稀疏,查询变得更快。因为以5000为stepSize, 其中可能有不少_id是不存在的。测试同学帮我搭线下测试数据时,2000w条数据,由于计算错误,_id的范围分布剧然从10亿起,到130亿止。导致的线程几乎一起在空跑chunk。所以_id分布稀疏的情况下,这种查询方式完全不适用。
3、 _id分布不均。可能某个chunk中几乎5000个满载,有些chunk只有很少几个_id有效。那么就会导致计算资源分布不均。
最后的结果不理想,我一开始,由于涉及一些联表join操作,用时16多个小时。后来各种调整,加线程,去掉一些操作,差不多仍需10小时。
五、改用散列片键后的较高效全表扫描方法
上面的那种方法,当然是不理想的。光查数据就需要16个小时,加上后续处理,肯定更久,这样我们的搜索引擎索引建立,就不可能当前完成了。但一直苦于没有更好的方法。
最终这个问题,还是被我的头解决了。 先说一下,最终效果吧。20w条/秒,约3小时完成。
其实,最终的方法很简单,但必须放弃多线程(多cursor)。
做法:使用单线程扫描,不加适合可能影响排序的条件。
这样做的目的是使用mongodb中的自然排序。扫描时,必然是依次命中某一个分片读取,不会带来磁盘震荡问题。
建索引用的是lucene, 索引结点分布在其他服务器上。文中所说的是去除了后续处理的代码,光扫描mogodb Collection的用时。
建索引用的是lucene, 索引结点分布在其他服务器上。文中所说的是去除了后续处理的代码,光扫描mogodb Collection的用时。
加我QQ,交流下吧,951514291
- 如何对10亿数据量级的mongoDB作高效的全表扫描
- 亿万数据量级mongoDB中高效查找同一字段的所有不同值集合
- 10亿级的mongodb进行全表扫描
- 如何更高效的对首页数据的展示
- MongoDB在58同城百亿量级数据下的应用实践
- CPU cost对全表扫描成本的影响
- mongodb的高效性
- mysql 千万量级的表的优化
- 全扫描的影响因素之数据舍弃的百分比
- 全表扫描和索引扫描的区别
- 全表扫描和索引扫描的区别
- 【转】让 InnoDB 的全表扫描快 10 倍
- 会引起全表扫描的10种SQL语句
- 亿量级流量的数据统计分析以及挖掘技术实战(Spark And Storm)
- 有关全表扫描的讨论
- 全表扫描下的逻辑读
- 会引起全表扫描的写法
- 导致全表扫描的SQL
- 【49】java内部类剖析
- 最长递增子序列
- 动画库 Tweenmax 使用示例2 - 事件和状态
- c++实验6-数组合并
- 最长公共递增子序列
- 如何对10亿数据量级的mongoDB作高效的全表扫描
- 第十三周实践项目4-立体类族共有的抽象类
- shiro处理两种路径进行登陆问题
- js base64加密
- SDUT-2170-The Largest SCC(强连通分量)
- 论函数调用约定
- 【数据库】视图 存储过程 触发器 事物
- Android6.0的通话记录获取
- 第13周阅读程序——交通工具(1)