在SQL语法中,经常用到GROUP BY来做多维度的聚合。但是遇到多个维度并列聚合的方式,通常是将每个维度用GROUP BY统计后,再使用UNION语法将结果集汇总,但是这样的SQL执行计划会在数据INPUT端从存储引擎获取多次,导致重复获取数据,浪费机器资源。CUBE、ROLLUP、GROUPING的语法可以更高效的做到多维度的聚合
SoftWare | Version |
---|---|
Presto | 0.149 |
Hive | 1.1.0-cdh5.11.1 |
Java | 1.8.0_121 |
此文会以Presto On Hive 的方式演示实例,Mysql不同版本支持不同,Oracle、Sql Server的语法方式略有差异
数据准备
建测试表
1 | CREATE TABLE `wxm_test_fun`( |
准备数据
1 | 1 wxm1 000 111 |
说明聚合维度
四个维度:id(0),name(1),area_id(2),group_id(3)
CUBE
cube会对所有聚合可能进行计算:CUBE(A,B,C),会计算group by A union group by B group by C union group by (AB) union group by (AC) union group by (BC) union group by (BC) union all (ABC)
分组的次数=2ⁿ-1;n为待分组的字段个数
1 | presto:temp> select id,name,area_id,count(*) count from wxm_test_fun group by cube(id,name,area_id) order by id,name,area_id; |
2的3次方减1 = 8个维度的整合
- 等价于8个union
1 | presto:temp> select * from ( |
ROLLUP
与CUBE不同,ROLLUP仅仅只展开第一层的维度聚合:分组的次数=待分组的字段数+1
cube会对所有聚合可能进行计算:CUBE(A,B,C),会计算group by y (ABC) union group by (AB) group by C union group by NULL
1 | presto:temp> select name,area_id,group_id,count(*) count from wxm_test_fun group by rollup(name,area_id,group_id) order by name,area_id,group_id,count(*); |
- 等价于3 + 1 = 4个union聚合
1 | presto:temp> select * from ( |
GROUPING SETS
对任意指定分组进行聚合
GROUPING SETS((AB),(A),(B),()),仅仅group by (AB) union group by A union group by B union group by null
1 | presto:temp> select id,name,area_id,count(*) count from wxm_test_fun group by grouping sets((id,name),name,area_id,()) order by id,name,area_id; |
- 等价于grouping sets中的字段union group by
1 | presto:temp> select * from ( |
维度信息获取
通常情况下,为了group by 的灵活性,通常会选用grouping sets,这就会出现一个维度标志问题。并不知道这个聚合数据哪个维度,通常可以用case when语句解决
- 以此句为例
1 | select id,name,area_id,count(*) count from wxm_test_fun group by grouping sets((id,name),name,area_id,()) order by id,name,area_id; |
(id,name)维度为维度01,name为维度02,area_id为维度03,()为全局维度
1 | presto:temp> select |
转载请注明出处:https://github.com/imperio-wxm