1、列裁剪和分区裁剪
- 列裁剪是在查询时只读取需要的列;
- 分区裁剪就是只读取需要的分区。
简单的说:select 中不要有多余的列,坚决避免 select * from tab;查询分区表,不读多余的数据;
select uid, event_type, record_data
from calendar_record_log
where pt_date >= 20190201 and pt_date <= 20190224
and status = 0;
2、sort by 代替 order by
HiveQL中的order by与其他关系数据库SQL中的功能一样,是将结果按某字段全局排序,这会导致所有map端数据都进入一个reducer中,在数据量大时可能会长时间计算不完。
如果使用sort by,那么还是会视情况启动多个reducer进行排序,并且保证每个reducer内局部有序。为了控制map端数据分配到reducer的key,往往还要配合distribute by 一同使用。如果不加 distribute by 的话,map端数据就会随机分配到reducer。
3、group by 代替 count(distinct)
当要统计某一列的去重数时,如果数据量很大,count(distinct) 会非常慢。原因与order by类似,count(distinct)逻辑只会有很少的reducer来处理。此时可以用group by 来改写:
-- 原始SQL
select count(distinct uid) from tab;
-- 优化后的SQL
select count(1)
from (select uid from tab group by uid) tmp;
这样写会启动两个MR job(单纯distinct只会启动一个),所以要确保数据量大到启动job的overhead远小于计算耗时,才考虑这种方法。当数据集很小或者key的倾斜比较明显时,group by还可能会比distinct慢。
4、group by 配置调整
(1)map端预聚合
group by时,如果先起一个combiner在map端做部分预聚合,可以有效减少shuffle数据量。
-- 默认为true
set hive.map.aggr = true
Map端进行聚合操作的条目数
set hive.groupby.mapaggr.checkinterval = 100000
通过hive.groupby.mapaggr.checkinterval 参数也可以设置map端