为了高效的使用Hive,需要对Hive进行性能优化。Hive常用性能优化方法如下
1、Hive的本地模式
需要处理的数据量不大,可以使用Hive的本地模式,该模式比Hadoop的集群模式运行速度要快,启用Hive本地模式的命令如下。
set hive.exec.mode.local.auto=true; //默认为false
set hive.exec.mode.local.auto.inputbytes.max=50000000; //输入的最大字节数,默认为128m
set hive.exec.mode.local.auto.input.files.max=8; //输入最大文件数,默认为4
注意:在shell中使用这些命令时需要把后面的注释去掉。
2、增加Hive的并行执行线程数,提高执行效率
Hive在执行查询语句时,会执行一个或者多个阶段(Stage),这些阶段常用于执行mapreduce任务、抽样、合并、limit等操作,Hive一般一次执行一个阶段。当Hive执行多个阶段时,并且这些阶段不存在依赖关系时,这些阶段可以并行执行,缩短执行时间,设置Hive的并行执行属性,并增加Hive并行执行线程数的命令如下。
set hive.exec.parallel=true; //默认为false
set hive.exec.parallel.thread.number=16; //默认执行的最大并行线程数为8
3、Hive的多表join优化
Hive在执行多表join操作时,使小表在左,大表在右。原因是Hive在执行多表Join时,会先将数据缓存起来,最后和后面的表进行连接,如果小表在前,缓存的数据相对较少。
4、 使用Map Join
如果一个表足够小,可以完全加载到内存中,那么Hive可以执行Map Join。自动启用Map Join和设置小表大小的命令如下。
set hive.auto.convert.join=true; //自动启用Map Join 默认为false
set hive.mapjoin.smalltable.filesize=600000000; //默认为25M
5、合理设置桶表连接(Bucket Map Join)。
在将大量数据进行Join时,使用Map Join会出现内存不足的情况,如果使用Bucket Map Join,就可以把少量桶的数据放到内存中进行Map Join操作。设置Bucket Map Join的命令如下:
set hive.auto.convert.join=true; //自动启用Map Join 默认为false
set hive.optimize.bucketmapjoin=true; //默认为false
6、使用左连接
当能够使用left semi join语句时,不要使用内连接,Left semi join对于左表中指定一条记录,一旦在右表中找到就立即停止扫描,效率更高。
LEFT SEMI JOIN (左半连接)是 IN/EXISTS 子查询的一种更高效的实现。
Hive 当前没有实现 IN/EXISTS 子查询,所以可以用 LEFT SEMI JOIN 重写你的子查询语句
7、使用limit优化
返回整个语句后的部分结果。设置启用limit优化的命令如下。
set hive.limit.optimize.enable=true;
8、数据倾斜优化
如果数据分布不均匀,导致数据倾斜,可以采用以下优化方式。
set hive.optimize.skewjoin=true; //默认为false
set hive.skewjoin.key=100000; //如果Key的个数超过该设定值,新的数据会发送给其它空闲的Reduce
9、group by操作优化。
Hive可以在Map阶段进行部分进行聚合操作,以此减少Reduce阶段的操作。而group by操作也是一种可以在Map阶段进行的聚合操作。
(1)、设置在Map阶段进行聚合。
set hive.map.aggr=true; //默认为true
(2)、设置Map阶段进行group by操作的条目数。
set hive.groupby.mapaggr.checkinterval=100000; //默认为100000条
Hive在使用group by时经常发生数据倾斜,可以进行如下优化。
set hive.groupby.skewindata=true; //默认为false
Hive设置好以上属性后,在使用group by时,会触发一个额外的MapReduce作业,改作业Map阶段的输出数据将被随机的发送到Reducer,以避免数据倾斜。
10、合并小文件
小于HDFS块大小的小文件数据过多,会大量占用HDFS的NameNode存储空间。合并小文件的命令如下:
set hive.merge.mapfiles=true //Map阶段合并小文件
set hive.merge.mapredfiles=true // MapReduce作业完成后合并小文件
set hive.merge.size.per.task=256000000 //设置作业完成后合并小文件的大小
set hive.merge.smalliles.avgsize=16000000 //设置触发合并小文件的阈值
11、设置Reduce个数
Hive在启用Mapreduce作业时,Reduce个数对作业执行效率低影响较大。如果未设置Reduce个数,Hive会通过以下两个属性来猜测确定Reducer个数:
1.hive.exec.reducers.bytes.per.reducer
2.hive.exec.reducers.max
Reduce个数N的计算公式如下:
N=min(2,总输入数据量/1)
在实际开发环境中,可以根据自身业务数据的特点设置上述两个属性,具体命令实例如下。
jdbc:hive2://> hive.exec.reducers.bytes.per,reducer=300000000
jdbc:hive2://> hive.exec.reducers.max=16
12、如果是由于业务逻辑的原因导致优化效果不明显,又是可以取出倾斜的数据1进行处理,之后将处理完的数据与元数据进行合并。
Hive优化补充:
1、表的优化
在表的优化中第一点:当数据量比较大的时候常用的手段就是为拆分表,大表拆小表,分区表 ,临时表 ,外部表
小表和大表join ,要把数据量的小的表放在join的左边,先进行缓存 ,这样减少表Join的时候内存的消耗量
2、严格模式
Hive中提供有严格模式,为了防止一些查询。出现不好的影响。例如笛卡儿积。在严格模式下是不能运行的
<property>
<name>hive.mapred.mode</name>
<value>strict</value>
<description>
The mode in which the Hive operations are being performed.
In strict mode, some risky queries are not allowed to run. They include:
Cartesian Product.
No partition being picked up for a query.
Comparing bigints and strings.
Comparing bigints and doubles.
Orderby without limit.
</description>
</property>
默认值为:非严格模式 nonstrict
开启严格模式: strict
开启了严格模式,会对查询语句进行一些限制:
(1) 对于分区表: 必须存在where语句对分区表中分区字段进行条件过滤,否则,不允许执行该查询
(2) 对于使用order by的语句必须使用limit 进行限定,由于order by 之后所有的数据都会被分到一个reduce中那这样reduce操作的数据量太多了,可能时间过长卡死。所以为了防止reduce时间过。在order by的时候必须给定 limit 减少redue处理的数据量
(3) 限制了笛卡儿积的查询 .主要在多表join中会出现。笛卡儿积的出现会造成性能极大的消耗
3、JVM重用
在hive执行计算任务的时候,会把的执行计划上传到yarn集群中进行提交,运行MR任务。每次进行任务的运行的时候都会开启一个JVM进程运行的MR任务。如果提交任务频繁过多就会造成JVM频繁的开启和关闭。在JVM开启和关闭的过程中会造成大量的资源浪费
在处理小文件的时候,由于map任务较多。所以JVM会频繁的开启和关闭。所以对于小文件的处理优化,主要减少JVM开启的次数
在 mapred-default.xml配置文件中有如下参数:
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
也可以在hive中临时设置JVM重用任务的运行数量
set mapreduce.job.jvm.numtasks
4、 推测执行
由于集群中的资源分配不均等,或者每个集群中节点的硬件性能,会导致某个任务运行的时间快或者某个任务运行的时间慢,或者某个任务在运行的时候直接卡死了
为了防止某些任务,在运行过程中,拖慢了整个MR任务的进度。在运行慢的任务节点上开启相同的任务,如果时间比原来的任务运行的快则直接输出推测运行的任务
设置开启推测执行的参数:
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks
may be executed in parallel.</description>
</property>
在hadoop中默认开启推测执行。推测执行不是说一卡死就开启任务必须运行%5以上才会开启推测执行
在hive中通过set参数也可以进行设置
set mapreduce.map.speculative=true
默认值为true
推测执行分为map端的推测执行以及reduce端的推测执行
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks
may be executed in parallel.</description>
</property>
5、执行计划
Hive中提供的可以查看Hql语句的执行计划,在执行计划中会生成抽象语法树,在语法树中会显示HQL语句之间的依赖关系以及执行过程。通过这些执行的过程和依赖可以对HQL语句进行优化
一般来说都会把复杂语句简单化处理。例如多表的Join。
Hive 查看执行计划的语句:
EXPLAIN [EXTENDED|DEPENDENCY|AUTHORIZATION] query
6.Fetch 抓取
现在hive中在运行查询任务的时候,很多时候都会运行mapreduce任务,在某些情况下,不需要运行MR任务 。这个时候就可以进行一些设置,设置什么情况下使用MR 任务 什么情况下不运行MR任务
在hive-defualt.xml配置文件中存在如下配置 :hive.fetch.task.conversion
<property>
<name>hive.fetch.task.conversion</name>
<value>more</value>
<description>
Expects one of [none, minimal, more].
Some select queries can be converted to single FETCH task minimizing latency.
Currently the query should be single sourced not having any subquery and should not have
any aggregations or distincts (which incurs RS), lateral views and joins.
0. none : disable hive.fetch.task.conversion
1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
</description>
</property>
1). 如果把hive.fetch.task.conversion设置为none 在运行任何查询语句的时候都会运行MR任务
set hive.fetch.task.conversion=none;
select ename from emp;
2). 如果把hive.fetch.task.conversion设置为more 也是默认的方式
以下查询方式不运行MR任务
使用 * 的方式不运行MR
select * from emp;
查询单个字段的方式不运行MR
使用limit 也不运行MR任务
select ename from emp limit 1;