问题起因:
项目上会对用户观看资源的记录进行数据打点,然后会对数据进行统计计算。用户要查询他自己的资源查看记录,这种操作如果用户量特别大,那这个数据量就会相当庞大。目前数据已突破E级。当处理这些数据的时候就会遇到很多问题。当然我这里处理的其实是通过加工后的数据。但是就算处理加工后的数据,查询也相当的慢。
1:获取今日数据,通过nosql语句,查询出昨日的网站所有数据。(200W左右)耗时4分钟左右
2:对数据进行分组 秒算 20000组左右
3:对每组的数据进行计算加工 秒算
4:与最后一次记录做对比,再计算,再加工 注:这期间就会出现问题了,因为这个操作是在循环内进行的。20000次查询,一个查询就算用1秒 这速度都是及其慢的。(记录表300万左右)
这里其实问题就很明显了:在循环内的单次查询300万级的表,我这边耗时是15秒左右甚至更高。这就导致我们的统计 极其的慢,而且极其的耗费mongoDB服务器的资源,甚至tomcat假死。
问题解决:
解决问题的办法其实很简单,加索引即可。但是在网上找了很久的资源,都没有明确的指出合理的加索引的方式,和加索引会不会引发其他问题的信息?
其实要解决这个问题也很简单,我们用了最笨的办法:模拟数据。在本地测试处理相当数据量的数据即可。
创建数据:
100W数据集合
测试:
无索引:10-15秒
带索引:5-10毫秒
1000W数据集合
测试
无索引:80-100秒
带索引:0.3-0.8秒
1E数据集合
测试
无索引:本地卡死
带索引:本地卡死
100W数据集合
测试
无索引:80-100秒
排序列索引:120-200秒
查询列索引:0.3-0.8秒
测试:
新增数据和查询数据时创建索引 无压力,mongoDB查询和插入都正常
这里其实看出一个问题,就是如果你查询时条件比较多,我这里是四个字段的查询带排序,单加排序索引其实是反效果。
通过本地测试,可以想象在线上服务器会优化到相当的程度
创建索引的命令格式:
db.表名.createIndex({字段名:1},{background: true})
相关文章可以参考菜鸟驿站:https://www.runoob.com/mongodb/mongodb-indexing.html
注意:
其实有朋友会问为什么不开线程来跑那20000次的查询,这里说明一下本人这边nosql没有做集群,是单服务在跑数据量其实并不是非常大,还能撑住。在上线完成之后测试过,单线程跑20000次查询,其实mongo服务器的压力就已经上来了,开多线程很可能会导致服务器负载而引起不必要的麻烦。
上线后,在服务器上的优化更明显,之前统计这部分数据 会耗时9小时左右,现在优化之后 4分钟就跑完了,对应的是9小时的mongo负载减少,提升是相当明显的。
奉劝大家,在设计表的时候,一定要考虑到数据量的问题。如果这张表数据会超过十万以上,那一定得先考虑索引的创建。