400万条数据存到本地,你会怎么存?
现在在维护一个项目,因为当初的数据库设计并不是我,所以现在被坑爽了。
该项目跑了一年多了,其他问题到没啥,就是报表那块很蛋疼。
这个项目是关于物联网的,其中有一个表,记录设备上下线(其中还有一个blob字段,这是最蛋疼的)。
由于大量设备频繁上下线,一年多,记录已经到达几千万,
而项目中,则是去查询该表一个月的记录(400万左右),并做成报表并导出成excel(有查询条件可以选择,选择后可能还是有200万左右)。
我测试过,(根据设备ID,且能创建索引的地方我都创建了)查询一个设备,一个月的记录所用时间为60秒左右。目前数据库中有2000个设备。(如果循环遍历。。)所用时间就是。。。。60 * 2000 大概是。。33.3小时。。
但这个事情必须解决啊,现在该数据库结构是不可能了,又不能删除以前的数据啊(毕竟才一年的数据也不是很久远),肿么办呢?我做了个很大胆的决定,将数据查询到本地内存中!!!
首先选用比较给力的JDBC(hibernate都没有用),然后,用ArrayList来装,结果。。。list装了30W 就挂了。。
内存溢出。。。汗。。 立即修改java虚拟机内存 果断1024M(我本机只有2G内存) 结果。。。也只能装60W左右。。
无助。。。。
几经周折,最终还是被我给拿下了。说说方法。
首先采用了HashMap,但这个Map有点“大” 在Map的value中我又存了个ArrayList 而Map的Key则是设备ID
查询的时候先查询出所有的设备ID(是另一个表,查询速度很快),再将查询出的所有设备Id都存到Map中,然后查询记录表,遍历每条记录,根据每天记录的设备Id,在在Map中找到Id对应的List,再进行list的add。。
这样摊下来,一个list的大小大约是 4000000 / 2000 = 2000。。。
这样 绝对不会内存益处了。
各位高手,如果是你们,你们会怎么做呢?
------解决方案--------------------肢解的正确,挺好的。
------解决方案--------------------你的报表需要每一次设备上下线的记录么?
我觉得应该不需要,应该是对几百万条数据做统计吧,那为什么不每天晚上跑下存储过程,把数据先统计好?你一个月400万,一天也就十几万,这个应该很快的。导报表直接查统计表就可以了。
------解决方案--------------------1,生成多个excel(一个excel包含多个sheet),然后打包成zip。
2,配置总数,导出最多导出多少条数据如300W(根据性能),
配置每个excel中有多少个sheet如10个(上线255),
配置每个excel中每个sheet的数量如5W(上线65536),
3,循环取数据,每次取生成一个A.excel的数量50W,将A.excel放在服务器上
4,最后将所有的excel打包。
ps:生成.csv的速度要快很多。
------解决方案--------------------你用4M长度的ArrayList放不下,没有可能用Hashmap放下。中间是不是改了数据结构?
------解决方案--------------------都是高人啊,看不懂。。。
------解决方案--------------------
你的存储过程是增量的么?如果是按日增量计算,每天才10几万条数据,不应该一样啊!你的上下线表明显是起的历史记录的作用,这个表在时间那个列上按天分区,存储过程只查某一天的数据应该会快很多才对啊。
------解决方案--------------------