目录
一、数据倾斜
分桶优化使用场景:优化大表和大表的join
原理:
二、运行时优化
三、编译时优化
四、union的优化
五、group by优化
六、presto内存优化
一、数据倾斜
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