目录
一、数据倾斜
1. 本地模式
-
设置参数
-
set hive.exec.mode.local.auto=true;
-
-
同时满足3个条件
-
输入的数据量大小小于128M
-
Maptask的个数小于等于3
-
reducetask的个数小于等于1
-
2.fetch抓取
-
设置参数
-
set hive.fetch.task.conversion=more; ###默认是more
-
设置为more之后,select*from table;select *from table limit 1;不会执行MapReduce过程
-
3.空key的处理
-
当事实表是日志类数据时,往往会有一些项没有记录到,我们试情况会将它置为null,或者空字符串,-1等。如果缺失项很多,在做join时这些空值就会非常集中,拖累进度。因此,若不需要空值数据,就提前写where语句过滤掉。需要保留的话,将空值key用随机方式打散。
4.join优化
4.1 map端的join优化
如果有reduce阶段,相同key的值发送到同一个reduce,某些 reduce可能因为处理的数据量过大,导致数据倾斜
为了避免数据倾斜,可以采用避免产生reduce阶段来解决,使用map端join策略
map 端join的相关参数
#开启map端join参数 set hive.auto.convert.join=true; #小表的参数,默认25M set hive.mapjoin.smalltable.filesize=25000000;
4.2bucket-mapjoin操作
如果两个表进行连接操作,一张表的数据比较小但是远远超过小表参数,而且这个SQL数据倾斜。一样采用在map端join操作,避免reduce阶段,从而解决数据倾斜的问题
使用桶表替代原来的表
1.创建两个桶表,发桶字段是连接字段 2.2个表的分桶个数呈倍数关系 3.将原来的表数据写入桶表里面,在SQL脚本用桶表替换原来的表
开启相关参数
---开启桶表的map端join优化 set hive.optimize.bucketmapjoin=true
4.3 SMB JOIN 优化方法
针对两个表的数据量都很大,非常容易产生数据倾斜。采用类似与map端join的方法,让两个大表连接到时候在map端进行连接,避免reduce阶段产生
优化方法
参数
---写入数据强制分桶 set hive.enforce.bucketing=true; ---写入数据强制排序 set hive.enforce.sorting=true; ---开启bucketmapjoin set hive.optimize.bucketmapjoin=true; ---开启SMB JOIN set hive.auto.convert.sortmerge.join=true; set hive.auto.convert.sortmerge.join.nocoditionaltask=true;
桶表的设置
1.创建2个桶表,分桶字段是连接字段 2.根据粪桶字段进行排序,而且2个表的排序是一样的 3.分桶个数保持一致
将原表数据写入分桶表,用桶表替换原来的表进行sort merge bucket join优化
分桶优化使用场景:优化大表和大表的join
原理:
-
如果大表和大表使用mapreduce的普通模式,会在reduce端shuffle,一是慢,二是容易出现异常
-
而分桶表将大表的数据划分为一个个小块,分别在Map端做join。之所以可以这样,是因为分桶表在建表的社会,需要指定分桶的字段,对这个字段值取hash后对桶的个数取余数获得一个值,根据这个值将数据放到不同的桶里去。相同key的数据都在一个桶里,在表和表关联的时候就不需要去扫描整个表,只需要扫描对应桶里的数据即可
-
由于不同的数据落到哪个桶是由分桶个数决定的,所以做join的两个分桶的同个数必须是相等或者成倍数
-
分桶表的每个桶必须要排序,这样可以更高效的做map join
5.code2
5.1 maptask code2问题
maptask调参
1.有次调度工具发送了告警邮件,开发的某个任务报错了 2.查看对应的脚本以及报错信息,发送报错的是map端的code2,当时查看信息发现mapper执行任务99%,任务进度就一直卡在99% 3.确认是map端的code2问题,原因是maptask处理的数据量过大导致的数据倾斜 4.调整单个maptask处理的数据量大小,默认为256m。将其调成300m,350m,400m,对应执行时间,发现300m跑的最快 set hive.exec.mappers.bytes.per.mapper=256000000; set hive.exec.mappers.bytes.per.mapper=300000000; 5.将的单个mapper处理的数据量大小定位300m
5.2 reducetask code2问题
1.某天调度工具发送告警日志,有个任务报错 2.查看任务对应的脚本和日志,发现是reduce端报数据倾斜code2.因为发现redduces执行任务进度到95%就不动了 error:MapRed reducetask code2 3.因为数据倾斜导致某个reducetask跑了很久没有执行成功,最后报错 4.调整单个reducer处理的数据量大小,默认为256M,将此参数改成300,350,400分别执行了一遍,发现在300m的时候执行的时间最短,因此将参数改为300m执行 set hive.exec.reducers.bytes.per.reducer=256000000; set hive.exec.reducers.bytes.per.reducer=300000000; 5.任务重启,执行成功
二、运行时优化
-
开启参数
-
set hive.optimize.skewjoin=true;
-
-
运行时的优化思想
-
当某个key的数据太大可能会导致数据倾斜,就将这些数据划分多个maptask来处理
-
三、编译时优化
-
开启参数
-
set hive.optimize.skewjoin.compiletime=true;
-
-
思想
-
已经只知道写入表数据的哪些字段的值会产生数据倾斜的可能,那么就在建表的时候指定会倾斜的字段,以及对应的值
-
CREATE TABLE list_bucket_single (key STRING,value STRING) -- 倾斜的字段和需要拆分的key值 SKEWED BY (cid) ON (01) -- 为倾斜值创建子目录单独存放 [STORED AS DIRECTORIES];
-
SKEWED BY (cid) :cid有可能会数据倾斜 ON (01):01代表这个值数据量比较大,可能倾斜
-
-
四、union的优化
-
当开启运行时的优化和编译时的优化之后,在所有的数据计算完,会将所有结果通过union all合并在一起,这样会产生一个MapReduce阶段,会增加任务的执行时间
-
如果想减少任务的执行时间,可以开启移除union阶段
-
好处
-
减少了任务的执行时间
-
-
坏处
-
会产生很多小文件
-
-
-
建议开启
-
---join运行时的优化 set hive.optimize.skewjoin=true; ---join编译时的优化 set hive.optimize.union.remove=true; ---当有运行时的优化或者编译时的优化,建议开启移除union操作 set hive.optimize.union.remove=true;
-
五、group by优化
5.1 2次mapreduce
-
开启参数
-
set hive.groupby.skewindata=true;
-
-
思想
-
1.第一次MapReduce的时候,reduce是随机拉去数据到本地,进行计算 2.第二次MapReduce的时候,相同key的值发送到同一个reduce进行计算,得到最终的结果
-
5.2 map端的预聚合
-
map端的预聚合
-
set hive.map.aggr=true;
-
-
思想
-
在map端处理完数据之后,在map端进行combiner,减少数据量 后续reduce阶段拉取的数据变少了,从而有效解决数据倾斜的问题
-
-
总结
-
group by的优化,都是从map阶段入手的,减少map阶段数据的输出,reduce阶段处理的数据量变少,从而有效避免数据倾斜
-
六、presto内存优化
1.presto常规优化手段
-
采用orc存储格式
-
Presto对ORC文件读取做了特定优化,因此在hive中创建Presto使用的表时,建议采用ORC格式存储。相对于Parquet,Presto对ORC支持更好
-
-
建议对数据进行压缩,因为snappy的解压速度更好,建议使用snappy
-
数据压缩可以减少节点间数据传输对IO带宽压力,对于即席查询需要快速解压,建议采用Snappy压缩
-
-
对数据进行预排序
-
合理设置分区个数
-
与hive类似,presto会根据元数据信息读取分区数据,合理的分区能减少presto数据读取量,提升查询性能
-
2.presto在sql上面的优化
-
不要写*查询数据
-
由于采用列式存储,选择需要的字段可以加快对字段的读取,减少数据量。避免采用*读取所有字段
-
-
根据分区查询数据
-
对于有分区的表,where语句中优先使用分区字段进行过滤
-
-
group by先对分组多的字段进行分组,然后再对分组少的进行group by
-
合理安排Group by语句中字段顺序对性能有一定提升,将group by语句中字段按照每个字段distinct数据多少进行降序排列
-
-
order by +limit
-
order by需要扫描数据到单个worker节点进行排序,导致单个worker需要大量内存。如果是查询Top N或者Bottom N,使用limit可减少排序计算和内存压力
-
-
regexp_like替代like
-
大表放左边
-
Presto中join的默认算法是mapjoin,即将join左边的表分割到多个worker,然后将join右边的表数据整个复制一份发送到每个worker进行计算。如果右边的表的数据量太大,则会报oom
-
当两个大表进行join是,使用hash join,先将大表按照hash算法分成多个小表,然后进行对应join,其实也是mapreduce思想
-
-
因为在presto里面会自动将左边的大表切割之后分发给每个worker,然后将右边的小表复制到每个worker里面进行处理
-
-
rank替代row_number
3.内存调优
-
当内存不够的时候可以适当调大用户内存,将第三方内存适当调小
-
面试题:presto的调优
-
内存调优
-
因为presto是一个内存式计算的引擎,非常消耗内存
-
presto的内存分为:预留内存和general内存。而预留内存长时间不用就资源浪费了,可以适当调小预留内存或者直接引用预留内存,调大用户内存
-
适当调小第三方内存,将内存加到用户内存里面,有效避免内存溢出oom
-
-