主要从四个方面进行优化:
注意:hive的性能好坏绝对与数据量的大小无关,就好比如你便秘跟你吃饭的多少有关系吗
1.分区表:
经常被使用的字段_dt,设置为分区表
举措:对常用的查询字段采用分区技术
2.分桶表:
哈希散列,一系列的记录按照哈希散列进行分布,一个分桶中会有多个不同的值,如果一个分桶中包含了某个值,那么这个值的所有的记录必然在这个分桶中。
分桶用到的场景:
1.加快join查询的一个速度:两个必须得是分桶表而且个数还得相同。在map时候都知道记载哪个桶了,所以在join会效率提升
2.采样:比如我们去分析一个数据的中位数,最大值最小值的统计,如果做这样的一个计算还需要全表扫描就很耗费性能,如果用了一个分桶表,从分桶表里拿一个数据,就能节省性能,因为这个数是一个哈希散列。
举措:对需要进行join和采样的情况,进行分桶操作
3.存储格式:
orc和parquet:均为列式存储
我们在维度建模的时候,在建的宽表一定要用orc格式,orc查询速度会比较快
举措:在建表时候选择列式存储,最好选用orc格式,提高查询速度
4.压缩格式:
决定mr的瓶颈是io,怎么解决io呢?那就是减少数据量,与磁盘的交互少了,时间就短了。
但是压缩的过程又要消耗cpu。
压缩方式:需要考虑的三要素:压缩率,压缩速度,是否可切片
其中gzip压缩率好但压缩效率低且不可分片,snappy不可分片但压缩速度快, lzo是可切片且压缩速度快,
选择lzo是最优的
5.合理设置map数、reduce数和小文件的处理:
5.1 Map数:
是不是保证每个map处理接近128m的文件块,就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数;
5.2对小文件进行合并:
6种方法:map执行前、map_only结束、map-reduce结束、per.task大小、smallfiles.avgsize、per.task大小
-
Map执行前:
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;--在 map 执行前合并小文件,以此来减少 map数:CombineHiveInputFormat 具有对小文件进行合并的功能 - //输出合并小文件
SET hive.merge.mapfiles = true;--在 map-only 任务结束时合并小文件,默认 true
SET hive.merge.mapredfiles = true;--在 map-reduce 任务结束时合并小文件,默认 false
SET hive.merge.size.per.task = 268435456;--合并文件的大小,默认 256M
SET hive.merge.smallfiles.avgsize = 16777216;--当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge - Reduce数调整测试
set hive.exec.reducers.bytes.per.reducer=256000000; 这个参数设置每个reduce任务处理的数据大小,可以动态计算reduce数量
5.3 Reduce数:
(1)过多的启动和初始化Reduce也会消耗时间和资源;
(2)另外,有多少个Reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
在设置Reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的Reduce数;使单个Reduce任务处理数据量大小要合适;