在项目开发过程中,使用hive进行数据处理和分析的时候经常会出现问题,如:GC,数据倾斜,这些都是老生常谈的问题了,下面概括几个常用的hive调优方法
Hive调优
1)map端join
1)如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成CommonJoin,即:在Reduce阶段完成join。
容易发生数据倾斜。可以用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理。
2)set hive.auto.convert.join=true;
2)行列过滤
行处理:在SELECT中,只拿需要的列,如果有,尽量使用分区过滤,少用SELECT*
列处理:表关联的时候,先在on前面加上过滤条件,这样会先过滤再关联表;如果在where后面加过滤条件,会先全表关联再过滤
3)使用Tez计算引擎
命令行:set hive.execution.engine=tez;
修改配置文件
4)采用分区、分桶技术
但少用动态分区
5)并行度优化
1)调整map数量
增加map数量的情况:任务产生的小文件大小接近块大小,但是文件的结构非常简单,只有一个或两个字段,却有上千万条的数据,如果map数量过少,每个map处理的逻辑又非常复杂的话,这也非常耗时。这时需要适当增加map数量去分担压力
减少map数量的情况:任务产生小文件过多,每个小文件大小远小于块大小(128M),每个小文件消耗一个map,map的启动和初始化时间远大于map的逻辑处理时间,这样非常消耗性能,浪费资源
2)调整reduce数量
通过修改参数手动设置reduce数量
根据数据量大小合理设置reduce数量
扩展:
mapTask数量由split切片决定,这里mapTask数量指的就是map数量:
1)文件大小小于128M(默认块大小),有多少个文件就有多少个mapTask
2)文件大小大于128M,根据切分规则,有多少个切分就有多少个mapTask
3)根据切片规则计算map数量的Hadoop中map源码公式:
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
(默认切片大小blockSize是128M,minSize大小默认是1M,maxSize默认>128M)
6)小文件问题
1)小文件合并:
map端开启combiner: set hive.map.aggr = true
合并map端输出文件: hive.merge.mapfiles = true
合并reduce端输出文件:hive.merge.mapredfiles = true
2)存储格式:
Sequencefile存储格式代替默认的textfile存储格式一定程度上可以减少小文件
7)存储格式、压缩格式
1)般企业里使用ORC或者Parquet,因为是列式存储,且压缩比非常高,查询速度快,占用硬盘空间少
2)ORCfile存储格式可以提高join查询速度
8)减少count(distinct)
使用distinct容易造成数据倾斜,因为用了distinct就无法在map端进行combiner操作,可能会导致reduce端拉取数据计算的时候因处理逻辑过于复杂、数据量过大而遇到瓶颈
9)设置本地模式、并行模式、严格模式
本地模式:set hive.exec.mode.local.auto=true;默认为false
并行模式:set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。
严格模式:hive的严格模式可以防止用户执行哪些可能产生不好影响的查询
开启严格模式需要将hive.mapred.mode的值从默认的nonstrict,修改为strict
开启严格模式会禁止以下操作:
1)限制笛卡尔积的查询
2)对于使用了order by语句的查询,后面必须接limit语句,防止处理排序的那个reducer执行时间过长
3)对于分区表,需要加上where 分区字段,不允许用户扫描全表,不允许扫描所有分区
10)开启JVM重用
在实际生产环境一般都会开启JVM重用
当小文件过多或者task特别多的时候,Hadoop默认配置通常是派生JVM来执行map和Reduce任务,一个task伴随一次JVM的启动和销毁,当一个job中包含成百上千个task任务时,JVM重用可以使得JVM实例在同一个job中重复使用n次,n的值在mapred-site.xml文件中配置。
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>通常在10-20之间,设定为-1表示无论task有多少个都重用一个JVM实例。</description>
</property>