需求:现有一个1000万行数据的日志文件,每行数据用TAB来分割,它们是userId,gameId,gameScore(用户ID,游戏ID(1--10),该用户在该游戏的这次得分),当数据库中的数据出现丢失,现在要根据该日志文件的记录来恢复数据库中的数据,也就是将该日志中的数据插入到数据库中。数据库中有四个字段:userId,gameId,maxScore,times,这个times是该玩家玩这个游戏的次数,maxScore是玩这个游戏的最高分。
数据库采用分库分表方式,4个表,在两个数据库中,DB1(Table0,Table1),DB2(Table3,Table3)。表单元为:500万(Table0存放userId在0---500万的用户数据,Table1存放userId在500w---1000w的用户数据.....)
解决方案一:
定义一个hashmap,用来存放要插入到数据库中的数据。HashMap<Key,Value> hashmap;Key类的字段:userId,gameId;Value类的字段:maxScore,times;
接下来就是读取日志文件,对每行进行处理:
如果hashmap中有该gameId和userId,那么根据该行的gameScore和maxScore进行比较,来更新maxScore,同时times++;
否则:hashmap.put(key,value);
最后得到一个统计所有数据的hashmap,再把数据批量插入到数据库中。
这是基本思路,但是这样好吗?1000万行数据啊。。且不说爆不爆内存,速度也是非常慢的,也许你会说hashmap不是查找很快么,但是存在hash冲突啊。1000万行数据要冲突多少次,每个链表 有多长啊!!查找还会快么。
解决方案二:
将所有数据映射到4*10=40个文件中,4为表数,10个gameId的数量。1_1,1_2.....1_10,.......4_10;
读取日志文件String line=reader.readline();
对每行数据进行处理:String[] infos=line.split("
");info[0]-->userId,info[1]-->gameId,info[2]-->gameScore。
userId为n,gameId为m,那么映射的文件为:n/5000000_m。这样就把数据放入到40个文件中了。
开始读取文件:进行解决方案一的处理。每个文件生成一个hashmap。再将hashmap批量插入数据库中。然后读取下一个文件,依次这么处理。。。
每个hashmap也就是平均存放25万行数据。爆不了内存,同时查找速度也不慢。经测试,到了200多万时会变得特别慢。
现在功能是完成了,但是你会发现当所有数据插入到数据库需要1个多小时,我的是每个文件2分钟多。这是一个相当漫长的等待。。。呜呜呜。。。
优化:对于mysql数据库,采用批量插入的同时设置:rewriteBatchedStatements=true。现在7秒一个文件。整个处理过程在4分钟之内就完成了。
代码就不上传。。