论坛首页 Java企业应用论坛

数据表每天五千四百万数据,,如何汇总

浏览 18924 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2015-01-09  
vanjayzhou 写道
一个java程序员 写道
这跟我做的一模一样,大数据汇总。  用的mysql, 也没什么办法。


直接内存汇总的。


汇总肯定是要查询所有的数据之后   才能计算,进行汇总操作。 

4.
汇总完后,最后还有个处理过程就是,汇总结果表table2中的主键id 需要回填进 table1 对应的记录(为了表明table1的记录汇总到了table2中的某条记录)。


这个处理 感觉不好吧? 还要操作数据源表? 更新操作吗?  会不会锁表?数据那么大。



根据表中四个字段(c1,c2,c3,c4)汇总 ,无论怎么做  这个汇总条件 查出的数据 都非常的大。 好像也没什么好方法。


这么多数据内存放不下的吧。。jvm Linux上最多支持不超过3g的内存。。而且数据库的数据的大小。。封装成对象后 size 远远比数据库中的数据大。。

能不能说下你的思路



我们的数据是24小时 不间断的入库的。

汇总也是在凌晨的一个时间。

mysql  几千万 数据, 怎么汇总我觉得都一样。  没什么方案不方案的。

5000W数据应该没问题吧   反正我们这个可以。


最好在入库之前 就进行内存汇总  然后入库。 这样数据库的数据就少的多了。  分批汇总 入库。 然后再分批汇总基础上 进行汇总。

我们在收到数据的时候,内存 10000条汇总一次, 然后入库。 
最后凌晨的时候  再次汇总,  分批汇总的数据。

0 请登录后投票
   发表时间:2015-01-09  
方案三, 将四个字段的某个字段作为分表维度, 这样子的结果就是,每个表中的汇总结果都会各自独立,不需要再次汇总, 缺点是 每张表的数据量可能不平均。



这个也不错。  我们就按照一个 字段 分表的  没有按照四个字段, 例如C1,根据获得的数据中C1  的数据 规则 分的。
这个局限一些。 例如 C1数据是电话号码  这种有规律的数据,可以按照 末尾号码分表。

不知道我这种有没有问题 暂时 我们这么做没问题、
0 请登录后投票
   发表时间:2015-01-09  
mark 说不定有用了呢。。
0 请登录后投票
   发表时间:2015-01-09  
vanjayzhou 写道
handong890 写道
你每次汇总一定要重头到尾计算一次?不能累加么? 建一张汇总记录表不就完了?几十亿的数据 都这样过来了



是可以累加。。关键是如何累加。。一条一条去数据表中累加么。。这样速度会不会很忙。

在内存中累加是最快的方法, 但结果集内存放的下么。。。


一条条累加?你不能在小表里面统计么?


你不会在数据库建一张汇总表么? 4K 多万的数据 你说你分小表10张-50张 每次汇总一张小表所有的数据 也就对应汇总表一条数据,你在根据小表的汇总表汇总不就是全量数据么?

我可以负责的告诉你上亿,几十亿的数据只是汇总DB分表绝对玩的转。这完全是不需要思考没有任何难度的事情
0 请登录后投票
   发表时间:2015-01-09  
不考虑使用大数据技术的情况下,分成大小差不多的小块,使用多线程计算,最后合并,会减少时间么?
0 请登录后投票
   发表时间:2015-01-10  
YES  
red008 写道
我理解每天4千多万条数据不是瞬间过来的。比如应该每天白天工作时间过来的数据,每个小时几百万。这样的话,汇总必须要等所有数据都过来之后进行才有意义。

那么,我认为合适的方案应该是:
1,白天按照工作时间,比如会传数据的时间是10个小时,那么按照10个小时分10个表。
第一个小时过来的数据都去第一个表,第二个小时过来的数据去第二个表,以此类推。

2,建立一个历史表,这个表你可以是按天的历史,也可以是按照周,月的历史,看你的汇总需求了。

3,第一个小时过去后,把第一个表的数据都导入历史表去,以此类推,直到下班后数据全都进入历史表里面。这样做的好处是,数据表的插入和读取是完全时间分离的,从理论上避免了死锁发生的可能性。

4,汇总统计从历史表里面抽取数据汇总,因为这时候历史表里面有今天所有的数据,所以你愿意怎么汇总就怎么汇总,根据你说的这一部分需求,应该几个SQL就搞定了吧。

5,如果你有按照周或者月汇总的需求,相应建立周汇总的历史表或者月汇总的历史表即可。这和你自己管理的总汇总记录可以互相验证,互相检查。

你可能会觉得这么大量数据插入历史表比较费时间,不过我认为你是一个小时左右去插几百万,时间完全够,而且这个插入是insert into select 小时表 的操作,全部是数据库侧的动作,会很快的。如果性能确实是问题,那么可以考虑历史表先不建立索引,最后10个小时的数据都进去之后再建立索引,这种插入速度是飞快的。

当然,如果你24小时全部有数据过来,那么我说的方案可能就不是很合适,不过如果是这样的需求话,你怎么做汇总都不会百分百精确的吧。

这个方案是根据你说的需求想的,估计你实际中有很多限制,不过我觉得应该是这个思路走下去。

0 请登录后投票
   发表时间:2015-01-12  
超大数据汇总方案(可靠)
1、读写程序1:拿到的数据先存储到本地文件中(你需要开发一个内存->文件同步功能,就是直接把数据写在内存,立马也会写到本地文件中;还需要限制大小,比如一个文件200M,按时间命名文件名)
注意:a1、这个地方首先只管存储数据,不要管任何逻辑!要谨记;
  a2、数据不要存储到mysql中,按照每天1000W,1个月就可以让你的数据库直接奔溃(估计几天就完了)

2、汇总程序1:此汇总程序1哪里读取数据(开多线程进行读取,这里需要根据CPU来确定要开多少线程,最好可配置),按照时间段进行汇总统计(比如:8:15、8:30、:9:00)
注意:a1、此应用程序主要是第一次汇总,比如1个文件是100W条数据,根据时间段累计,汇总完毕后就知道1W条数据,这样数据就变小了
  a2、如果你的汇总数据需要按类型汇总,则线程也需要按类型划分;记得同种类型只交给同种线程进行汇总
  a3、这里因为是多线程且数据量大,在使用java的时候,数据对象在同一类型线程中不要new,只要一个,用完重置即可;不然会出现内存溢出;
 
3、汇总程序2:次汇总程序需要跟你的项目需求来定制,看看是否需要把时间段缩小在继续汇总,逻辑与汇总程序1一样

4、入库程序:把汇总的文件上传到mysql服务器,直接使用mysql -e "" 方式入库,不要使用jdbc
注意:这里的入库文件格式必须与表字段一致

最后:大概细节都说明了,这个方案是可用的
0 请登录后投票
   发表时间:2015-01-12  
yschysn 写道
超大数据汇总方案(可靠)
1、读写程序1:拿到的数据先存储到本地文件中(你需要开发一个内存->文件同步功能,就是直接把数据写在内存,立马也会写到本地文件中;还需要限制大小,比如一个文件200M,按时间命名文件名)
注意:a1、这个地方首先只管存储数据,不要管任何逻辑!要谨记;
  a2、数据不要存储到mysql中,按照每天1000W,1个月就可以让你的数据库直接奔溃(估计几天就完了)

2、汇总程序1:此汇总程序1哪里读取数据(开多线程进行读取,这里需要根据CPU来确定要开多少线程,最好可配置),按照时间段进行汇总统计(比如:8:15、8:30、:9:00)
注意:a1、此应用程序主要是第一次汇总,比如1个文件是100W条数据,根据时间段累计,汇总完毕后就知道1W条数据,这样数据就变小了
  a2、如果你的汇总数据需要按类型汇总,则线程也需要按类型划分;记得同种类型只交给同种线程进行汇总
  a3、这里因为是多线程且数据量大,在使用java的时候,数据对象在同一类型线程中不要new,只要一个,用完重置即可;不然会出现内存溢出;
 
3、汇总程序2:次汇总程序需要跟你的项目需求来定制,看看是否需要把时间段缩小在继续汇总,逻辑与汇总程序1一样

4、入库程序:把汇总的文件上传到mysql服务器,直接使用mysql -e "" 方式入库,不要使用jdbc
注意:这里的入库文件格式必须与表字段一致

最后:大概细节都说明了,这个方案是可用的

不错
0 请登录后投票
   发表时间:2015-01-12  
如果只是计算一次,分表,然后合并统计。

如果考虑长远的话,还是上大数据平台。不过还要考虑人力,资金,和领导的支持。
0 请登录后投票
   发表时间:2015-01-20  

扩展一下楼主的方案二,使用多线程的异步更新的方式。

逻辑如下图:

 

线程汇总的逻辑伪代码如下:

	// 全局Map缓存,保存每条唯一数据对应的ID
	Map<String,Long> statIdMap = new ConcurrentHashMap<String, Long>();
	
	// 线程内Map,保存线程内统计结果
	Map<Long,BigDecimal> statMap = new HashMap<Long,BigDecimal>();
	// 线程内List, 保存回填数据的ID列表
	List<Object[]> idList = new ArrayList<Object[]>(5000);
	// 明细数据列表
	List<Object> dataList;
	public void run(){
		Long statId = null; 
		String key = null;
		BigDecimal money = null;
		for(int i=0,j=dataList.size();i<j;i++){
			// 根据字段值生成KEY
			//key = dataList.get(i).getA()+dataList.get(i).getB()+dataList.get(i).getC()+dataList.get(i).getD();
			// 先从缓存中查询是否ID存在
			statId = statIdMap.get(key);
			// 如果缓存中不存在,则表示是第一次出现,应该先插入一条记录到数据库
			if(statId == null){
				// 初始化到数据库,默认累计金额为0
				// getStatId()方法插入数据库使用  insert ignore into 防止多线程插入时覆盖已存在数据
				//statId = getStatId();
				// 重新保存到缓存中
				statIdMap.put(key, statId);
			}
			money = statMap.get(statId);
			// 累计金额
			if(money == null){
				//money = dataList.get(i).money;
			}else{
				//money.plus(dataList.get(i).money);
			}
			statMap.put(statId, money);
			// 记录回填ID
			//idList.add(new Object[]{dataList.get(i).id, statId});
		}
		
		// 加入到待更新队列
		// idListQueue.addAll(idList);
		// 把统计好的数据添加到更新队列
		// statIdStatQueue.add(statMap.entrySet().iterator().next());
		
		// idListQueue       数据结构  Queue<[明细ID,统计ID]>
		// statIdStatQueue   数据结构 Queue<[统计ID,金额]>
	}

 

 

代码逻辑主要有三点:1.数据分配、2.每个线程的统计逻辑、3.统计结果使用队列单线程异步批量更新到数据库。

 

需求来说:统计汇总还算正常逻辑,还要把统计后的id回填到明细中去就有点变态了。

 

  • 大小: 53.7 KB
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics