Code Bye

合并两张表的统计结果,数据大,可以用SQL或JAVA

 

环境:java、mysql数据库
情景:A表有t1、t2、t3、t4
      B表有t1、t2、t3、t4
A、B表的结构是一模一样的。现在的需求是对A表根据t1、t2、t3、t4进行分组得到结果集(countA、t1、t2、t3、t4),countA是各分组的记录数,B表操作同A表一样。最后要的结果集是(countB、t1、t2、t3、t4).
最后还要统计A表字段t5为success、wait状态的分组得到countAA,即:同A表一样先进行(t1、t2、t3、t4)分组统计,条件为t5字段的值为success或wait。结果集为:(countAA、t1、t2、t3、t4)。
最终得到的结果集为(countA、countAA、countB、t1、t2、t3、t4)。

我的思路是,分三次分组统计,最后根据t1、t2、t3、t4把3个临时表合并。但因为有几百万的数据,实际操作中分组字段还有增加,单对A表进行分组统计都需好十几秒,合并临时表更是耗时,搞不好数据库表会被锁死。

我还尝试过分3次查询,然后在java代码中对3个结果集进行for循环,然后根据t1、t2、t3、t4属性相等条件来合并结果集。但这样的循环有最低几十亿次,耗时也太长。

有人给个思路么,用sql 或者 java代码解决都行。
在线等!很急。

好难的样子,坐等高人
引用 1 楼 MrsFeng 的回复:

好难的样子,坐等高人

表示需求很简单,可这数据量一大我就hold不住了。

已过10分钟,坐等大神来解惑。人工置顶!
引用 楼主 l568646976 的回复:

最后还要统计A表字段t5为success、wait状态的分组得到countAA,即:同A表一样先进行(t1、t2、t3、t4)分组统计,条件为t5字段的值为success或wait。结果集为:(countAA、t1、t2、t3、t4)。

这个什么搞笑要求?countAA是count(t5)的结果,怎么会要求得到(countAA、t1、t2、t3、t4),这什么逻辑关系?
没弄清楚需求吧。

引用 4 楼 zxcvbnm11920 的回复:
Quote: 引用 楼主 l568646976 的回复:

最后还要统计A表字段t5为success、wait状态的分组得到countAA,即:同A表一样先进行(t1、t2、t3、t4)分组统计,条件为t5字段的值为success或wait。结果集为:(countAA、t1、t2、t3、t4)。

这个什么搞笑要求?countAA是count(t5)的结果,怎么会要求得到(countAA、t1、t2、t3、t4),这什么逻辑关系?
没弄清楚需求吧。

我怕大家搞混才这样写的,其实是这样的,t5其实就是t4,countAA是group by字段t1、t2、t3、t4,条件为t4是success、wait值

5楼写错了。t5就是t5,countAA是group by字段t1、t2、t3、t4,where条件为t4是success、wait值 

40分
引用 5 楼 l568646976 的回复:

我怕大家搞混才这样写的,其实是这样的,t5其实就是t4,countAA是group by字段t1、t2、t3、t4,条件为t4是success、wait值

先别管这sql效率怎么样,这个sql符合你的要求吗?

select a.a, aa.aa, b.b, a.t1, a.t2, a.t3, a.t4
  from (select count(1) a, t1, t2, t3, t4 from A group by t1, t2, t3, t4) a
  left join (select count(1) aa, t1, t2, t3, t4
               from A where t4 = ""success"" group by t1, t2, t3, t4) aa
    on a.t1 = aa.t1
   and a.t2 = aa.t2
   and a.t3 = aa.t3
   and a.t4 = aa.t4
  left join (select count(1) b, t1, t2, t3, t4
               from B group by t1, t2, t3, t4) b
    on b.t1 = aa.t1
   and b.t2 = aa.t2
   and b.t3 = aa.t3
   and b.t4 = aa.t4
需求我看的有点乱。你最好能举个简单的列子说清楚需求
比如
A表字段
t1,t2,t3,t4
B表字段
t1,t2,t3,t4

期望的结果是怎样?

引用 8 楼 huxiweng 的回复:

需求我看的有点乱。你最好能举个简单的列子说清楚需求
比如
A表字段
t1,t2,t3,t4
B表字段
t1,t2,t3,t4

期望的结果是怎样?

我感觉楼主搞不定的原因就是不能把需求转化成清晰问题,两张表的问题,要求再复杂,也不会存在特别难道的地方。


20分
帮你顶顶。。。
引用 7 楼 zxcvbnm11920 的回复:
Quote: 引用 5 楼 l568646976 的回复:

我怕大家搞混才这样写的,其实是这样的,t5其实就是t4,countAA是group by字段t1、t2、t3、t4,条件为t4是success、wait值

先别管这sql效率怎么样,这个sql符合你的要求吗?

select a.a, aa.aa, b.b, a.t1, a.t2, a.t3, a.t4
  from (select count(1) a, t1, t2, t3, t4 from A group by t1, t2, t3, t4) a
  left join (select count(1) aa, t1, t2, t3, t4
               from A where t4 = ""success"" group by t1, t2, t3, t4) aa
    on a.t1 = aa.t1
   and a.t2 = aa.t2
   and a.t3 = aa.t3
   and a.t4 = aa.t4
  left join (select count(1) b, t1, t2, t3, t4
               from B group by t1, t2, t3, t4) b
    on b.t1 = aa.t1
   and b.t2 = aa.t2
   and b.t3 = aa.t3
   and b.t4 = aa.t4
引用 8 楼 huxiweng 的回复:

需求我看的有点乱。你最好能举个简单的列子说清楚需求
比如
A表字段
t1,t2,t3,t4
B表字段
t1,t2,t3,t4

期望的结果是怎样?

就是7楼这个想法,但这样查询太慢了。

引用 9 楼 zxcvbnm11920 的回复:
Quote: 引用 8 楼 huxiweng 的回复:

需求我看的有点乱。你最好能举个简单的列子说清楚需求
比如
A表字段
t1,t2,t3,t4
B表字段
t1,t2,t3,t4

期望的结果是怎样?

我感觉楼主搞不定的原因就是不能把需求转化成清晰问题,两张表的问题,要求再复杂,也不会存在特别难道的地方。

需求是很简单,就是你7楼说的那样,估计现在你也弄清了。sql查询出来是很容易,想要效率。因为数据量多,一次查询需要很久

引用 11 楼 l568646976 的回复:

就是7楼这个想法,但这样查询太慢了。

发下执行计划看看,给你优化下。还有结果一共多少条?

引用 13 楼 zxcvbnm11920 的回复:
Quote: 引用 11 楼 l568646976 的回复:

就是7楼这个想法,但这样查询太慢了。

发下执行计划看看,给你优化下。还有结果一共多少条?

一张表大概有150万数据

引用 14 楼 l568646976 的回复:

发下执行计划看看,给你优化下。还有结果一共多少条?

一张表大概有150万数据
汗我问执行计划和结果一共有多少条。
这个数据这么多在内存里计算不好,直接用sql搞定得了。才150W数据耗时不会太高的,可以优化。

引用 15 楼 zxcvbnm11920 的回复:
Quote: 引用 14 楼 l568646976 的回复:

发下执行计划看看,给你优化下。还有结果一共多少条?

一张表大概有150万数据

汗我问执行计划和结果一共有多少条。
这个数据这么多在内存里计算不好,直接用sql搞定得了。才150W数据耗时不会太高的,可以优化。sql和你在7楼写的基本一致。唯一不同的是,A表其实是2张表通过UNION连接起来的,B表也是2张表通过UNION连接起来。
单张表查询执行结果保守估计十万条左右。


15分
数据量大的情况,还需要从数据库本身入手去解决问题,可以考虑建立索引、视图或临时表来解决这种问题。
引用 17 楼 baohuan_love 的回复:

数据量大的情况,还需要从数据库本身入手去解决问题,可以考虑建立索引、视图或临时表来解决这种问题。

你说的 都用了。。。


15分
1,如果是数据库表设计的有问题,没法;
2,尝试各种表连接与过虑,看哪种更好。
引用 18 楼 l568646976 的回复:

你说的 都用了。。。

你描述总是没重点,现在到底多慢?多少秒?把sql发出来,执行计划也发出来。sql优化这种问题,你不发出来关键东西,别人怎么告诉问题出在哪。

引用 20 楼 zxcvbnm11920 的回复:
Quote: 引用 18 楼 l568646976 的回复:

你说的 都用了。。。

你描述总是没重点,现在到底多慢?多少秒?把sql发出来,执行计划也发出来。sql优化这种问题,你不发出来关键东西,别人怎么告诉问题出在哪。

sql代码涉及字段太多了,发出来根本看不懂,解释字段要很久。sql结构就是你7楼说的那样。整个查询,查15%的数据大概要5分钟以上(粗略估算)。


10分
两结果集union all,聚合一次,用行转列一次出来那几个查询列。
教你个笨办法,把sql从小范围向大范围查哪里慢。
如:
select *
  from (select *
          from (select * from a) a
          left join (select * from b) b
            on a.a = b.b) c
 where c.c = 1

先试

select * from a

再试

select * from b

再试

select *
  from (select * from a) a
  left join (select * from b) b
    on a.a = b.b

到哪一步突然慢特别慢,这里就是效率瓶颈,想办法优化。在经验不丰富的时候,可以使用这个简单方法能查出来大部分问题。

引用 23 楼 zxcvbnm11920 的回复:

教你个笨办法,把sql从小范围向大范围查哪里慢。
如:

select *
  from (select *
          from (select * from a) a
          left join (select * from b) b
            on a.a = b.b) c
 where c.c = 1

先试

select * from a

再试

select * from b

再试

select *
  from (select * from a) a
  left join (select * from b) b
    on a.a = b.b

到哪一步突然慢特别慢,这里就是效率瓶颈,想办法优化。在经验不丰富的时候,可以使用这个简单方法能查出来大部分问题。

很感谢你一直回答我的疑问。其实是因为group by的字段太多了,因为数据一多,分组就慢了。最后缩短了分组字段个数这个问题就告一段落了。

每次进行一次分组,结果集放到中间表中,再对结果集分组,再存储

然后查询你统计好并存储起来的结果集,每次都查询的话,确实扛不住

类似物化视图

撸主还是先把需求搞清楚,想要的结果是什么,再来用SQL来实现吧。
首先数据库字段要建索引,这样查询效率会提高吧。
发现一点就是t4是success、wait值,是不是t4就判断这两个值呢?如果是那应该分开来这么些或许会好些:
select t1, t2, t3, t4 from A group by t1, t2, t3 where t4=””success””或者t4=””wait””,就是先把想要的数据过滤出来,然后group by中就不要加t4了,这样效率会快些。
楼主的sql实际上比下面这个还要复杂:
select a.a, aa.aa, b.b, a.t1, a.t2, a.t3, a.t4
  from (select count(1) a, t1, t2, t3, t4 from A group by t1, t2, t3, t4) a
  left join (select count(1) aa, t1, t2, t3, t4
               from A where t4 = “”success”” group by t1, t2, t3, t4) aa
    on a.t1 = aa.t1
   and a.t2 = aa.t2
   and a.t3 = aa.t3
   and a.t4 = aa.t4
  left join (select count(1) b, t1, t2, t3, t4
               from B group by t1, t2, t3, t4) b
    on b.t1 = aa.t1
   and b.t2 = aa.t2
   and b.t3 = aa.t3
   and b.t4 = aa.t4
因为A和B都是两个表union来的,所以A和B实际上都是嵌套的子查询。
楼主最后不得不减少了分组字段解决速度的问题,其实是放弃了查询需求来凑合了。
我认为,做不下去的原因是SQL几个很重要的缺点造成的:不能分步计算、集合化不彻底、集合没有顺序还有没有对象引用机制。
如果这个问题用Java来写,应该是分成若干步骤的,每一步都不会太复杂,优化也比较容易。而且某些中间结果是可以复用的,不用像SQL那样算多遍。
用Java写的前提条件是把数据表从库中搬出来,放到文件系统中,这样做的好处是文件数据可以预先排序。而且可以避免Java读取mysql数据库的jdbc传输缓慢的问题。
提升性能比较有效的办法是把这个任务分成三个,用不同的计算机上的Java程序同时计算,最后归并结果。也就是并行计算。并行计算对性能的提升就很明显了。
但是,Java来完成这个有点困难,一个是没有现成的group、条件过滤、结果集归并等函数,还有就是Java并行程序比较难写。
可以考虑一下集算器(esProc),可以分步计算,访问文件数据很容易,结构化类库很全,并行程序也有现成的架构,写起来比较简单。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明合并两张表的统计结果,数据大,可以用SQL或JAVA