目录
💟这里是CS大白话专场,让枯燥的学习变得有趣!
💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话!
💟好记性不如烂键盘,自己总结不如收藏别人!
💌本篇继续总结HIve优化相关知识~
🧡小表Join大表&大表Join小表(MapJoin)
💌当用join连接一个小表和一个大表时,若用MR执行操作则join在Reduce操作阶段,而如果采用MapJoin执行操作则join在Map操作阶段。
💌Mapjoin把小表映射成HashTable,再加载到每个Map的内存中,大表作为Map的输入,直接连接内存中的小表数据。
💌没有Reduce阶段,避免数据倾斜;没有Shuffle阶段,减少IO。
🍠参数设置:
set hive.auto.convert.join = true; //默认为true
set hive.mapjoin.smalltable.filesize = 25000000; //默认25M以下认为是小表
🧡大表Join大表
空key过滤
💌由于空key会发送到同一个Reducer上,当空key(值为NULL)数量太多且为异常数据时,会导致数据倾斜,增加不必要的耗时,因此我们需要在Join之前先对空key进行过滤。
🍠使用场景:非Inner Join,如Left Join;不需要字段为NULL的。
不过滤空key
select a.* from A a left join B b on a.id = b.id;
过滤A.id中空key
select a.* from (select * from A where id is not null) a left join B b on a.id = b.id;
空key转换
💌当空key是非异常数据,需要保留时,可以对其先进行转换,随机赋一个值(不能影响join结果),使空key分散到不同Reducer上。
select a.* from A a full join B b on nvl(a.id,rand()) = b.id;
SMB(Sort Merge Bucket join)
💌对两张表join字段分桶,由于分桶后每个桶内hash值相同,在查询时只需要在对应的桶内查询即可,减少了查询时间。
🍠参数设置:
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
🧡Group By
💌我们知道当同一个key的数据过大时会产生数据倾斜,我们可以在Map端先进行聚合,对查询任务生成两个MR操作:
🍠第一个MR:将相同的Map输出结果拼接一个随机数,随机均匀分布到Reduce中,每个Reduce做部分聚合操作,并输出结果。相同的Group By Key有可能被分发到不同的Reduce中,实现负载均衡。
🍠第二个MR:再根据预处理的数据结果按照Group By Key分布到Reduce中,最后完成最终的聚合操作。相同的Group By Key被分布到同一个Reduce中。
🍠参数设置:
set hive.map.aggr = true; //是否在Map端进行聚合,默认为True
set hive.groupby.mapaggr.checkinterval = 100000; //在Map端进行聚合操作的条目数目
set hive.groupby.skewindata = true; //有数据倾斜的时候进行负载均衡,默认是false
Count(distinct)去重
💌count(distinct)查询只有一个Reducer,会导致整个Job难以完成,在数据量大时,可以将count(distinct)改为group by+count增加Reducer个数,相当于并行去重。
set mapreduce.job.reduces = 5;
select count(distinct id) from A;
select count(id) from (select id from A group by id) a;
🧡行列过滤
列过滤
💌尽量使用分区过滤。
行过滤
💌先where过滤,再关联。
select
a.id
from
A a
join (select id from A where id <= 10) b
on
a.id = b.id;
谓词下推
💌保证结果正确的前提下,当join on条件为where过滤条件时(id),谓词(where过滤条件)逻辑会提前执行(Map阶段),减少下游处理的数据量。
🍠参数设置:
set hive.optimize.pdd = true; //默认为true
🧡合理设置Map&Reduce数
Map
🍠文件大,任务逻辑复杂,可以调小maxSize,让maxSize<blocksize增加Map数,公式如下:
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
set mapreduce.input.fileinputformat.split.maxsize=100;
🍠在Map执行前合并小文件,减少Map数:
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
🍠在MR任务结束时合并小文件:
SET hive.merge.mapfiles = true; //在map-only任务结束时合并小文件,默认true
SET hive.merge.mapredfiles = true; //在MR任务结束时合并小文件,默认false
SET hive.merge.size.per.task = 268435456; //合并文件的大小,默认256M
SET hive.merge.smallfiles.avgsize = 16777216; //当输出文件的平均大小小于该值时,启动一个独立的MR任务进行文件merge
Reduce
🍠计算Reducer数的公式
N = min(hive.exec.reducers.max,总输入数据量/hive.exec.reducers.bytes.per.reducer)
hive.exec.reducers.bytes.per.reducer=256000000; //每个Reduce处理的数据量默认是256MB
hive.exec.reducers.max=1009; //每个任务最大的Reduce数,默认为1009
🍠在Hadoop的mapred-default.xml文件中修改,设置每个job的Reduce个数:
set mapreduce.job.reduces = 15;
🧡并行执行
💌在系统资源比较空闲的时候可以开启并行执行,没有依赖关系的Stage可以同时执行。
set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8
🧡严格模式
分区表
💌对于分区表,有时候也会进行全表查询,设置以下参数为true,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。
hive.strict.checks.no.partition.filter=true; //默认false
order by
💌设置以下参数为true,使用了order by语句的查询,要求必须使用limit语句。
hive.strict.checks.orderby.no.limit=true; //默认false
笛卡尔积
💌两个表join时一定要写有效的on条件,设置以下参数为true,不会产生笛卡尔积。
hive.strict.checks.cartesian.product=true; //默认true
🧡JVM重用
💌设置多个小文件共用一个Java虚拟机。