
文章字数:13271字
预计阅读需:18分钟
有需要可 点赞+在看 关注公众号《大数据阶梯之路》找小编获取文档保存本地吧,学习和复习都是绝佳,公众号不断分享技术相关文章
一、问题背景
主要从以下几个角度来考虑问题解决
从数据任务本身hive逻辑代码出发,即hive逻辑优化,偏理解业务角度
从集群的资源设置出发,即hive参数调优,偏理解技术角度
从全局数据链路的任务设置出发,观测是否任务执行调度设置不合理
从数仓的数据易用性和模型复用性的角度出发,针对某些中间逻辑过程可以复用的就落地中间模型表
附上一份个人梳理总结的思维导图部分截图

下面就先分享下常见的hive优化策略吧~会附带案例实践帮助理解会附带案例实践帮助理解
hive优化文章大纲
列裁剪和分区裁剪
提前数据收敛
谓词下推(PPD)
多路输出,减少表读取次数写多个结果表
合理选择排序
join优化
合理选择文件存储格式和压缩方式
解决小文件过多问题
distinct 和 group by
参数调优
解决数据倾斜问题
二、hive优化
1. 列裁剪和分区裁剪
裁剪 顾名思义就是不需要的数据不要多查。列裁剪,尽量减少直接select * from table这种操作,首先可读性不好,根本不知道具体用到哪几个列,其次列选择多了也会增大IO传输;分区裁剪就是针对分区表切记要加上分区过滤条件,比如表以时间作为分区字段,要加上分区筛选。
2. 提前数据收敛
在子查询中,有些条件能先过滤的尽量放在子查询里先过滤,减少子查询输出的数据量。
3. 谓词下推(Predicate Pushdown)
谓词下推Predicate Pushdown是什么?简称PPD,指的是在不影响数据结果的情况下,将过滤表达式尽可能移动至靠近数据源的位置,以使真正执行时能直接跳过无关的数据降低了数据在集群上传输的量,节约了集群的资源,也提升了任务的性能所谓下推,即谓词过滤在map端执行;所谓不下推,即谓词过滤在reduce端执行。

核心判断逻辑:join的on条件过滤不能下推到保留行表中;where条件过滤不能下推到null补充表中。
— 举例说明:以下脚本 on后面的a表条件过滤没有下推至map端运行而是在reduce端运行,where后面的b表条件过滤则有下推至map端运行select a.字段a,a.字段b,b.字段a,b.字段bfrom table_a aleft join table_b bon a.字段a <> ” — a表条件过滤where a.字段b <> ‘xxx’ — a表条件过滤;
谓词下推注意事项:
因为上面unix_timestamp()是不确定函数,在编译的时候无法得知,所以,整个表达式不会被下推,即ds=’2022-07-04’也不会被提前过滤。类似的不确定函数还有rand()函数等。
!上链接,自行复制去访问哈
① https://cloud.tencent.com/developer/article/1616687
② https://cloud.tencent.com/developer/article/1616689
4. 多路输出
当我们有使用一次查询,多次插入的场景时,则可以采用多路输出的写法,减少表的读取次数,起到性能优化的作用。
多路输出注意事项:
一般情况下,一个sql里面最多支持128路输出,超过了则会报错
在多插往同一张分区表的不同分区时,不允许在一个sql里面多路输出时既包含insert overwrite和insert into,要统一操作
5. 合理选择排序
order by
sort by
distribute by
cluster by
取用户信息表(10亿数据量)中年龄排前100的用户信息
排序选择的小结:
order by全局排序,但只有一个reducer执行,数据量大的话容易计算不过来,慎用
sort by局部排序,单个reducer内有序,把map端随机分发给reduce端执行,如果是要实现全局排序且走多个reducer的优化需求时,可以在外层嵌套一层,例如:select * from (select * from 表名 sort by 字段名 limit N) order by 字段名 limit N,这样就有2个Job,一个是内层的局部排序,一个是外层的归并全局排序
distribute by可以按照指定字段将数据进行hash分发到对应的reducer去执行
当分区字段和排序字段相同时可以使用cluster by来简化distribute by+sort by的写法,但是cluster by排序只能是升序排序,不能指定排序规则是ASC或者DESC
6. join优化
hive在redurce阶段完成的join就是common join,在map阶段完成的join就是map join。
提前收敛数据量,保证在join关联前无用数据不参与关联
left semi join左半关联虽然left semi join含有left,但其实不是保留左表全部数据,效果类似于join吧,只是最终结果只取左表中的列,还有最终结果某些场景下会跟join结果不同。
left semi join注意事项:
右表的条件过滤只能写在on后面,不能写在where后面
最终结果只能展示左表的列,右表的列不能展示
left semi join与join的差异:主要在于右表有重复数据时,left semi join是遍历到右表一条数据后就跳过,只取一条,而join是一直遍历至右表最后一条数据,这也就是要注意实际数据场景是否有重复和是否要保留
大表join小表场景这是因为join操作发生在reduce阶段,在hive2.x版本以前,位于左边的表会被加载进内存中,所以如果是大表放左边被加载进内存的话就会有内存溢出的风险
启用mapjoin
大表join大表场景
1、空key过滤,过滤空key的数据
2、空key转换,转换key的数据进行关联时打散key
避免笛卡尔积
7. 合理选择文件存储格式和压缩方式
!上链接
8. 解决小文件过多问题
先来说一说什么是小文件,怎么发生的
从公式上看,reduce的个数和分区数最终决定了输出的文件的个数,所以可以调整reduce的个数以及分区 达到控制hive表的文件数量。
小文件过多有什么影响
如何解决小文件过多问题
1、使用hive自带的 concatenate 命令,来合并小文件
2、调整参数减少Map数
设置map输入合并小文件
设置map输出和reduce输出合并小文件
3、调整参数减少Reduce数
9. count(distinct ) 和 group by
但如果数据量大count distinct就很耗性能了,因为其只会用一个reduce task来执行,容易reduce端数据倾斜
注意事项:所以还是具体业务场景具体分析为好,优化从来不是考虑局部就好,要全局考虑。
hive3.x版本里已经新增了对count(distinct )的优化,通过set hive.optimize.countdistinct配置,即使真的出现数据倾斜也可以自动优化,自动改变SQL执行的逻辑
里层group by age然后再外层count(user_id)这种方式会生成2个job任务,会消耗更多的磁盘网络I/O资源
10. 参数调优
set hive.optimize.countdistinct=true开启对count(distinct )的自动优化
set hive.auto.convert.join = true;开启自动mapjoinset hive.mapjoin.smalltable.filesize=26214400;大表小表的阈值设置(默认25M一下认为是小表)
set hive.exec.parallel=true;打开任务并行执行set hive.exec.parallel.thread.number=16;同一个sql允许最大并行度,默认值为8。默认情况下,Hive一次只会执行一个阶段。开启并行执行时会把一个sql语句中没有相互依赖的阶段并行去运行,这样可能使得整个job的执行时间缩短。提高集群资源利用率,不过这当然得是在系统资源比较空闲的时候才有优势,否则没资源,并行也起不来。
生成的查询计划有两个MapReduce任务
set hive.mapred.mode=strict;设置严格模式,默认值是nonstrict非严格模式。严格模式下会禁止以下3种类型不合理查询,即以下3种情况会报错
对于查询分区表,必须where加上分区限制条件
使用order by全局排序时,必须加上limit限制数据查询条数
限制了笛卡尔积查询
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;设置map端执行前合并小文件
set hive.exec.compress.output=true;设置hive的查询结果输出是否进行压缩set mapreduce.output.fileoutputformat.compress=true;设置MapReduce Job的结果输出是否使用压缩
set hive.cbo.enable=false;关闭CBO优化,默认值true开启,可以自动优化HQL中多个JOIN的顺序,并选择合适的JOIN算法
11. 解决数据倾斜问题
什么是数据倾斜数据倾斜是大量的相同key被partition分配到同一个reduce里,造成了’一个人累死,其他人闲死’的情况,违背了并行计算的初衷,而且当其他节点计算好了还要等待这个忙碌节点的计算,效率就被拉低了
数据倾斜的明显表现任务进度长时间维持在99%,查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大
数据倾斜的根本原因是什么?key分布不均匀,redurce数据处理不均匀
如何尽量避免数据倾斜如何将数据均匀的分配到各个reduce中,就是避免数据倾斜的根本所在。举例下2个典型案例,关于join操作发生的数据倾斜和解决方案:就在文章上面的第六点join优化【大表join大表场景】,还有合理设置map数和reduce数的解决方案。
合理设置map数和reduce数
1、Map端优化
减少map数量,降低资源浪费,如何做?以下相当于是把小文件合并成大文件处理 (多合一)
有时候对hive进行优化,在执行时间上可能没什么大的改观,但是在计算资源上就有很大改善。
增大map数量,分担每个map处理的数据量提升任务效率,如何做?以下相当于是把小文件合并成大文件处理 (一拆多)
根据mapreduce切片的公式:computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize))),从公式可以看出调整maxSize最大值,让maxSize最大值低于blocksize就可以增加map的个数。
mapreduce.input.fileinputformat.split.minsize(切片最小值),默认值=1,参数调的比blockSize大,则可以让切片变得比blocksize还大,从而减少map数mapreduce.input.fileinputformat.split.maxsize(切片最大值),默认值=blocksize块大小,参数如果调到比blocksize小,则会让切片变小,从而增大map数
2、Reduce端优化
那么:①reduce数是不是越多越好?答案是错误的,同map数一样,启动reduce和初始化同样耗时和占资源,而且过多的reduce会生成多个文件,同样会出现小文件问题。②什么情况下当设置了参数指定reduce个数后还是只有单个reduce在跑?
本身输入数据量就小于1G
在做测数据量验证时没加group by分组汇总。比如select count(1) from test_table where dt = 20201228;
用了order by排序
关联出现了笛卡尔积
合理设置map数和reduce数的小结:
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; //系统默认格式,设置在map执行前合并小文件,减少map数
set mapreduce.input.fileinputformat.split.maxsize = 100; //调整最大切片值,让maxSize值低于blocksize就可以增加map数
从公式可以看出调整maxSize最大值,让maxSize最大值低于blocksize,从而使切片变小,就可以增加map的个数
三、总结
日常hive开发中时刻养成提前数据收敛的习惯,避免无用数据参与到计算中
不要过度进行优化,有可能做的是无用功甚至产生负效应,在调优上投入的工作成本和回报不成正比
对于公共可复用的逻辑代码,可以抽取出来落地临时表或者中间表,提升复用性,强调复用!
理解hiveQL底层执行的原理,优化起来才有章可循
理透需求是代码优化的前提,关注全局数据链路,一些常见的hive优化策略要懂
做hive优化的时候,涉及到参数调优时要慎重,比如把内存都申请抢占满了,避免因为你自己的任务调优了但影响到整个集群其他任务的资源分配,全局优才是优!
分享就到此结束了,建议收藏吸纳消化,博文不易,欢迎👏🏻点赞+转发+收藏,更多精彩好文,尽在公众号《大数据阶梯之路》










暂无评论内容