hive的高级分组聚合是指在聚合时使用GROUPING SETS、CUBE和ROLLUP的分组聚合。

高级分组聚合在很多数据库类SQL中都有出现,并非hive独有,这里只说明hive中的情况。

使用高级分组聚合不仅可以简化SQL语句,而且通常情况下会提升SQL语句的性能。

1.Grouping sets 的使用

示例:

-- 使用方式
select a,b,sum(c) from tbl group by a,b grouping sets(a,b)

Grouping sets的子句允许在一个group by 语句中,指定多个分组聚合列。所有含有Grouping sets 的子句都可以用union连接的多个group by 查询逻辑来表示。

如下一些常见的等价替换示例:

-- 语句1
select a, b sum(c) from tbl group by a,b grouping sets((a,b))
-- 相当于
select a,b,sum(c) from tbl group by a,b -- 语句2
select a,b,sum(c) from tbl group by a,b grouping sets((a,b),a)
-- 相当于
select a,b,sum(c) from tbl group by a,b
union
select a,null ,sum(c) from tbl group by a -- 语句3
select a,b,sum(c) from tbl group by a,b grouping sets(a,b)
-- 相当于
select a,null,sum(c) from tbl group by a
union
select null ,b,sum(c) from tbl group by b -- 语句4
select a,b,sum(c) from tbl group by a,b grouping sets((a,b),a,b,())
-- 相当于
select a,b,sum(c) from tbl group by a,b
union
select a,null,sum(c) from tbl group by a
union
select null,b,sum(c) from tbl group by b
union
select null,null,sum(c) from tbl

可以看到通过等价替换的改写之后,语句会变得简洁,性能我们之后分析。

2.cube 和rollup的使用

示例:

-- cube使用示例
select a,b,c,count(1) from tbl group by a,b,c with cube
-- rollup使用示例
select a,b,c,count(1) from tbl group by a,b,c with rollup

用法说明:

以上两个高级分组函数都可以在一个group by 语句中完成多个分组聚合,它们都可以用grouping sets来等价替换。

  • cube 会计算所有group by 列的所有组合
-- cube语句
select a,b,c,count(1) from tbl group by a,b,c with cube
-- 相当于
select a,b,c count(1) from tbl group by a,b,c
grouping sets((a,b,c),(a,b),(b,c),(a,c),(a),(b),(c),())
  • rollup 会按照group by 指定的列从左到右进行分组聚合
-- rollup语句 滚动式聚合
select a,b,c,count(1) from tbl group by a,b,c with rollup
-- 相当于
select a,b,c,count(1) from tbl group by a,b,c s
grouping sets((a,b,c),(a,b),(a),())

3.使用高级分组聚合函数的性能分析

我们可以通过执行计划的执行来分析高级分组聚合SQL语句的执行过程,比对其优化的节点。

例1 含grouping sets关键词的SQL执行案例。

set hive.map.aggr=true;
explain
-- 小于30岁人群的不同性别平均年龄
select gender,avg(age) as avg_age from temp.user_info_all where ymd = '20230505'
and age < 30
group by gender; -- 将以上语句改为grouping sets关键词执行语句
set hive.map.aggr=true;
explain
select gender,avg(age) as num from temp.user_info_all
where ymd = '20230505'
and age < 30
group by gender grouping sets((gender));

查看其执行计划:

STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-0 depends on stages: Stage-1 STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan
alias: user_info_all
Statistics: Num rows: 32634295 Data size: 783223080 Basic stats: COMPLETE Column stats: NONE
Filter Operator
predicate: (age < 30) (type: boolean)
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
Group By Operator
aggregations: avg(age)
keys: gender (type: int), 0 (type: int)
mode: hash
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
Reduce Output Operator
key expressions: _col0 (type: int), _col1 (type: int)
sort order: ++
Map-reduce partition columns: _col0 (type: int), _col1 (type: int)
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
value expressions: _col2 (type: struct<count:bigint,sum:double,input:bigint>)
Reduce Operator Tree:
Group By Operator
aggregations: avg(VALUE._col0)
keys: KEY._col0 (type: int), KEY._col1 (type: int)
mode: mergepartial
outputColumnNames: _col0, _col2
Statistics: Num rows: 5439049 Data size: 130537176 Basic stats: COMPLETE Column stats: NONE
pruneGroupingSetId: true
Select Operator
expressions: _col0 (type: int), _col2 (type: double)
outputColumnNames: _col0, _col1
Statistics: Num rows: 5439049 Data size: 130537176 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed: true
Statistics: Num rows: 5439049 Data size: 130537176 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink

对以上内容进行关键字解读:

map阶段:

  • Group By Operator :Map端开启聚合操作
  • aggregations:分组聚合的算法,该案例采取avg(age)
  • keys: 这里是分组列+ 一个固定列 0
  • mode:Hash
  • outputColumnNames:最终输出三列。_col0, _col1, _col2
  • Reduce Output Operator:该阶段为map阶段聚合后的操作
  • key expressions:map端最终输出的key,该例为gender和0两列。
  • sort order:输出两列都正序排序
  • Map-reduce partition columns:表示Map阶段数据输出的分区列,该案例为gender和0两列进行分区。
  • value expressions:map端最终输出value,为一个结构体。

Reduce阶段:

  • Group By Operator:reduce阶段的分组聚合操作。
  • aggregations: 分组聚合算法,avg(VALUE._col0)表示对map阶段输出的 value expressions的 _col0取平均值。
  • keys:指定分组聚合的key,有两列。为map阶段输出的key。
  • mode: mergepartial
  • outputColumnNames: 表示最终输出的列,该例为gender和num。
  • pruneGroupingSetId: 表示是否对最终输出的grouping id进行修剪,如果为true,则表示将keys最后一列抛弃。案例中为0列。
  • Select Operator:进行列投影操作。
  • expressions:输出的列。gender和num。

通过查看以上的执行计划,可以看出在使用含有grouping sets语句的SQL中,hive执行计划并没有给出具体的实现细节。

再执行具有多个聚合列的实例来看看:

例2 聚合年龄和聚合性别多列合并测试。

set hive.map.aggr=true;
explain
select gender,age,count(0) as num from temp.user_info_all
where ymd = '20230505'
and age < 30
group by gender,age grouping sets(gender,age);

注:grouping sets后进行分组的列一定要在之前的group by中进行申明。

STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-0 depends on stages: Stage-1 STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan
alias: user_info_all
Statistics: Num rows: 32634295 Data size: 783223080 Basic stats: COMPLETE Column stats: NONE
Filter Operator
predicate: (age < 30) (type: boolean)
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
Group By Operator
aggregations: count(0)
keys: gender (type: int), age (type: bigint), 0 (type: int)
mode: hash
outputColumnNames: _col0, _col1, _col2, _col3
Statistics: Num rows: 21756196 Data size: 522148704 Basic stats: COMPLETE Column stats: NONE
Reduce Output Operator
key expressions: _col0 (type: int), _col1 (type: bigint), _col2 (type: int)
sort order: +++
Map-reduce partition columns: _col0 (type: int), _col1 (type: bigint), _col2 (type: int)
Statistics: Num rows: 21756196 Data size: 522148704 Basic stats: COMPLETE Column stats: NONE
value expressions: _col3 (type: bigint)
Reduce Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: int), KEY._col1 (type: bigint), KEY._col2 (type: int)
mode: mergepartial
outputColumnNames: _col0, _col1, _col3
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
pruneGroupingSetId: true
Select Operator
expressions: _col0 (type: int), _col1 (type: bigint), _col3 (type: bigint)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed: true
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink

通过以上两个例子可以看出hive执行计划中没有具体的高级分组聚合如何实现分组方案。两者执行方式基本上差不多。

在数据扫描和查询上的确减少了多次数据扫描和数据io操作。在一定程度上节省了计算资源。

例3 使用cube替代grouping sets 。

set hive.map.aggr=true;
explain
select gender,age,count(0) as num from temp.user_info_all
where ymd = '20230505'
and age < 30
group by gender,age with cube; -- 等价语句
select gender,age,count(0) as num from temp.user_info_all
where ymd = '20230505'
and age < 30
group by gender,age grouping sets((gender,age),(gender),(age),());
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-0 depends on stages: Stage-1 STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan
alias: user_info_all
Statistics: Num rows: 32634295 Data size: 783223080 Basic stats: COMPLETE Column stats: NONE
Filter Operator
predicate: (age < 30) (type: boolean)
Statistics: Num rows: 10878098 Data size: 261074352 Basic stats: COMPLETE Column stats: NONE
Group By Operator
aggregations: count(0)
keys: gender (type: int), age (type: bigint), 0 (type: int)
mode: hash
outputColumnNames: _col0, _col1, _col2, _col3
Statistics: Num rows: 43512392 Data size: 1044297408 Basic stats: COMPLETE Column stats: NONE
Reduce Output Operator
key expressions: _col0 (type: int), _col1 (type: bigint), _col2 (type: int)
sort order: +++
Map-reduce partition columns: _col0 (type: int), _col1 (type: bigint), _col2 (type: int)
Statistics: Num rows: 43512392 Data size: 1044297408 Basic stats: COMPLETE Column stats: NONE
value expressions: _col3 (type: bigint)
Reduce Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: int), KEY._col1 (type: bigint), KEY._col2 (type: int)
mode: mergepartial
outputColumnNames: _col0, _col1, _col3
Statistics: Num rows: 21756196 Data size: 522148704 Basic stats: COMPLETE Column stats: NONE
pruneGroupingSetId: true
Select Operator
expressions: _col0 (type: int), _col1 (type: bigint), _col3 (type: bigint)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows: 21756196 Data size: 522148704 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed: true
Statistics: Num rows: 21756196 Data size: 522148704 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink

以上例3 cube语句和例2语句输出数据完全是不一样的。但其输出执行计划内容基本和例2一致。可以看出hive的执行计划对高级分组聚合拆分执行计划的支持还不是很好。

使用高级分组聚合,要注意开启map端聚合模式。

使用高级分组聚合,如上案例,仅使用一个作业就能够实现union写法需要多个作业才能实现的逻辑。

从这点上来看能够减少多个作业在磁盘和网络I/O时的负担,是一种优化。

但是同时也要注意因过度使用高级分组聚合语句而导致的数据急速膨胀问题。

  • 通常使用简单的group by 语句,一份数据只有一种聚合结果,一个分组聚合通常只有一个记录;

  • 使用高级分组聚合,例如cube,在一个作业中一份数据会存在多种聚合情况,最终输出是,每种聚合情况各自对应一条数据。

注意事项:

如果使用高级分组聚合的语句处理的底表,在数据量很大的情况下容易导致Map或者Reduce任务因硬件资源不足而崩溃。

hive中使用hive.new.job.grouping.set.cardinality 配置项来应对以上情况。

如果SQL语句中处理分组聚合情况超过该配置项指定的值,默认值为(30),则会创建一个新的作业。

下一期:hive窗口分析函数解读以及带窗口分析函数的SQL性能分析

按例,欢迎点击此处关注我的个人公众号,交流更多知识。

后台回复关键字 hive,随机赠送一本鲁边备注版珍藏大数据书籍。

什么是hive的高级分组聚合,它的用法和注意事项以及性能分析的更多相关文章

  1. [Hive_11] Hive 的高级聚合函数

    0. 说明 Hive 的高级聚合函数 union all | grouping sets | cube | rollup pv //page view 页面访问量 uv //user view 访问人 ...

  2. row_number() over partition by 分组聚合

    分组聚合,就是先分组再排序,可以的话顺手标个排名:如果不想分组也可以排名:如果不想分组同时再去重排名也可以 ROW_NUMBER() OVER( [PARTITION BY column_1, col ...

  3. Atitit  数据存储的分组聚合 groupby的实现attilax总结

    Atitit  数据存储的分组聚合 groupby的实现attilax总结 1. 聚合操作1 1.1. a.标量聚合 流聚合1 1.2. b.哈希聚合2 1.3. 所有的最优计划的选择都是基于现有统计 ...

  4. ORACLE字符串分组聚合函数(字符串连接聚合函数)

    ORACLE字符串连接分组串聚函数 wmsys.wm_concat SQL代码: select grp, wmsys.wm_concat(str) grp, 'a1' str from dual un ...

  5. oracle 高级分组

    oracle 高级分组 博客分类: 数据库基础 oraclesql  10.高级分组 本章目标: 对于增强的group by需要掌握: 1.使用rollup(也就是roll up累计的意思)操作产生s ...

  6. SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表

    SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 2013-10-09 23:09 by BI Wor ...

  7. MySQL最常用分组聚合函数

    一.聚合函数(aggregation function)---也就是组函数 在一个行的集合(一组行)上进行操作,对每个组给一个结果. 常用的组函数: AVG([distinct] expr) 求平均值 ...

  8. solrcloud jsonfacet分组聚合 unique计数不准确

    jsonfacet分组聚合查询 unique.hll函数问题: 对不同的值进行估算,并非准确的值, 优点:节省内存消耗,用分组算法对不同的值count进行估算 缺点:无法准确统计count(disti ...

  9. Oracle 高级排序函数 和 高级分组函数

    高级排序函数: [ ROW_NUMBER()| RANK() | DENSE_RANK ] OVER (partition by xx order by xx) 1.row_number() 连续且递 ...

  10. 微软BI 之SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表

    基于数据仓库上的 SSRS 报表展示,一般可以直接通过 SQL 查询,存储过程,视图或者表等多种方式将数据加载并呈现在报表中.但是如果是基于 Cube 多维数据集的数据查询,就不能再使用 SQL 的语 ...

随机推荐

  1. python入门教程之二十三Python3 MySQL 数据库连接 - PyMySQL 驱动

    MySQL 是最流行的关系型数据库管理系统,如果你不熟悉 MySQL,可以阅读我们的 MySQL 教程. 本章节我们为大家介绍使用 mysql-connector 来连接使用 MySQL, mysql ...

  2. AtCoder Beginner Contest 061 - D Score Attack

    给定一张边带权的有向图.从节点\(1\)出发,每经过一条边一次,得分加上这条边的边权.(可以多次经过,多次累加 必须在点\(n\)结束游戏 判断是否能使得分无限大,如果否,求最大得分. sol 题目所 ...

  3. 一文吃透Arthas常用命令!

    Arthas 常用命令 简介 Arthas 是Alibaba开源的Java诊断工具,动态跟踪Java代码:实时监控JVM状态,可以在不中断程序执行的情况下轻松完成JVM相关问题排查工作 .支持JDK ...

  4. 点亮LED灯_STM32第一课

    基本原理 初始化Hal库 HAL_Init(); 系统时钟 SystemClock_Config();   GPIOB初始化:GPIOB模式为推挽输出,GPIO引脚为Pin_5.0.1代表红绿蓝LED ...

  5. Thread面试题

    面试题目录https://www.cnblogs.com/Kaelthas/p/15005844.html 1.一个Thread对象代表一个线程,同一个线程能否多次启动? 不能,在Thread类中变量 ...

  6. 《花雕学AI》17:关注提示工程—本世纪最重要的技能可能就是与AI人工智能对话

    本文目录与主要结构 引言:介绍提示工程的概念和背景,说明为什么它是本世纪最重要的技能之一. 正文: 一.提示工程的基本原理和方法:介绍什么是提示.如何设计和优化提示.如何使用提示与语言模型进行交互. ...

  7. 靶机渗透【billu_b0x】

    ip扫描 访问80端口 目录扫描 逐个访问 上传一个图片马,结果没有回显 显示file参数为空.请在"文件"参数中提供文件路径 打开发现有用户名 ![] 发现数据库连接的配置信息, ...

  8. LeetCode 周赛 340,质数 / 前缀和 / 极大化最小值 / 最短路 / 平衡二叉树

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 上周跟大家讲到小彭文章风格的问题,和一些朋友聊过以后,至少在算法题解方面确定了小彭的风格 ...

  9. HTML+CSS+JavaScript作业篇

    一.作业题大全 1.1.HTML5表单验证 代码: <!DOCTYPE html> <html lang="en"> <head> <me ...

  10. 18-html压缩

    const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); modul ...