[Hive进阶]-- Hive 优化

由于Hive的执行依赖于底层的MapReduce作业,因此对Hadoop作业的优化或者对MapReduce作业的调整是提高Hive性能的基础。所以我们可以通过一系列的调优方法,来提高大幅度地Hive查询的性能。

1、启用压缩

压缩可以使磁盘上存储的数据量变小,通过降低I/O来提高查询速度。

查出所使用的Hive版本支持的压缩编码方式,下面的set命令列出可用的编解码器(CDH 5.8.x中的Hive)。

 hive> set io.compression.codecs; 
 io.compression.codecs=
 org.apache.hadoop.io.compress.DefaultCodec,
 org.apache.hadoop.io.compres s.GzipCodec,
 org.apache.hadoop.io.compress.BZip2Codec,
 org.apache.hadoop.io.compress.DeflateCodec,
 org.apache.hadoop.io.compress.SnappyCodec,
 org.apache.hadoop.io.compress.Lz4Codec
hive>

一个复杂的Hive查询在提交后,通常被转换为一系列中间阶段的MapReduce作业,Hive引擎将这些作业串联起来完成整个查询。可以将这些中间数据进行压缩。这里所 说的中间数据指的是上一个MapReduce作业的输出,这些输出将被下一个MapReduce作业作为输入数据使用。我们可以在hive-site.xml文件中设置hive.exec.compress.intermediate 属性以启用中间数据压缩。

<property>
<name>hive.exec.compress.intermediate</name>
<value>true</value>
<description> This controls whether intermediate files produced by Hive between multiple map-reduce jobs are compressed. The compression codec and other options are determined from hadoop config variables mapred.output.compress* </description> </property>
<property>
<name>hive.intermediate.compression.codec</name> <value>org.apache.hadoop.io.compress.SnappyCodec</value>
<description/>
</property>
<property>
<name>hive.intermediate.compression.type</name>
<value>BLOCK</value>
<description/>
</property>

也可以在Hive客户端中使用set命令设置这些属性。

hive> set hive.exec.compress.intermediate=true;
hive> set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec; 

hive> set hive.intermediate.compression.type=BLOCK;
hive>

当Hive将输出写入到表中时,输出内容同样可以进行压缩。我们可以设置hive.exec.compress.output属性启用最终输出压缩。

<property>
<name>hive.exec.compress.output</name>
<value>true</value>
<description> This controls whether the final outputs of a query
(to a local/hdfs file or a Hive table) is compressed. The compression codec and other options are determined from hadoop config variables mapred.output.compress* </description>
</property>

或者

hive> set hive.exec.compress.output=true;
hive> set mapreduce.output.fileoutputformat.compress=true;
hive> set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec; 
hive> set mapreduce.output.fileoutputformat.compress.type=BLOCK;
hive>

2.优化连接

可以通过配置Map连接和倾斜连接的相关属性提升连接查询的性能。

(1)自动Map连接

当连接一个大表和一个小表时,自动Map连接是一个非常有用的特性。如果启用了该特性,小表将保存在每个节点的本地缓存中,并在Map阶段与大表进行连接。开 启自动Map连接提供了两个好处。首先,将小表装进缓存将节省每个数据节点上的读取时间。其次,它避免了Hive查询中的倾斜连接,因为每个数据块的连接操作已经在 Map阶段完成了。设置下面的属性启用自动Map连接属性。

<property> 
<name>hive.auto.convert.join</name> 
<value>true</value>
</property>
<property> 
<name>hive.auto.convert.join.noconditionaltask</name> 
<value>true</value>
</property> 
<property>
<name>hive.auto.convert.join.noconditionaltask.size</name>
<value>10000000</value> 
</property>
<property> 
<name>hive.auto.convert.join.use.nonstaged</name> 
<value>true</value>
</property>

说明

hive.auto.convert.join:是否启用基于输入文件的大小,将普通连接转化为Map连接的优化机制。

扫描二维码关注公众号,回复: 8586380 查看本文章

hive.auto.convert.join.noconditionaltask:是否启用基于输入文件的大小,将普通连接转化为Map连接的优化机制。假设参与连接的表(或分区)有N个,如果打开这个 参数,并且有N-1个表(或分区)的大小总和小于hive.auto.convert.join.noconditionaltask.size参数指定的值,那么会直接将连接转为Map连接。

hive.auto.convert.join.noconditionaltask.size:如果hive.auto.convert.join.noconditionaltask是关闭的,则本参数不起作用。否则,如果参与连接的N个表(或分区)中的N-1个 的总大小小于这个参数的值,则直接将连接转为Map连接。默认值为10MB。

hive.auto.convert.join.use.nonstaged:对于条件连接,如果从一个小的输入流可以直接应用于join操作而不需要过滤或者投影,那么不需要通过MapReduce的本地任务在 分布式缓存中预存。当前该参数在vectorization或tez执行引擎中不工作。

(2)倾斜连接

两个大表连接时,会先基于连接键分别对两个表进行排序,然后连接它们。Mapper将特定键值的所有行发送给同一个Reducer。例如,表A的id列有1、2、3、4四个

值,表B的id列有1、2、3三个值。查询语句如下:

select A.id from A join B on A.id = B.id

一系列Mapper读取表中的数据并基于键值发送给Reducer。如id=1行进入Reducer R1,id=2的行进入Reducer R2等。这些Reducer产生A、B的交集并输出。Reducer R4只从 A获取行,不会产生查询结果。

现在假设id=1的数据行是高度倾斜的,则R2和R3会很快完成,而R1需要很长时间,将成为整个查询的瓶颈。配置倾斜连接的相关属性可以有效优化倾斜连接。

<property> <name>hive.optimize.skewjoin</name> 
<value>true</value>
</property> <property>
<name>hive.skewjoin.key</name>
<value>100000</value> 
</property>
<property> <name>hive.skewjoin.mapjoin.map.tasks</name> 
<value>10000</value>
</property> 
<property>
<name>hive.skewjoin.mapjoin.min.split</name>
<value>33554432</value> 
</property>

说明:

hive.optimize.skewjoin:是否为连接表中的倾斜键创建单独的执行计划。它基于存储在元数据中的倾斜键。在编译时,Hive为倾斜键和其他键值生成各自的查询计 划。


hive.skewjoin.key:决定如何确定连接中的倾斜键。在连接操作中,如果同一键值所对应的数据行数超过该参数值,则认为该键是一个倾斜连接键。

hive.skewjoin.mapjoin.map.tasks:指定倾斜连接中,用于Map连接作业的任务数。该参数应该与hive.skewjoin.mapjoin.min.split一起使用,执行细粒度的控制。

hive.skewjoin.mapjoin.min.split:通过指定最小split的大小,确定Map连接作业的任务数。该参数应该与hive.skewjoin.mapjoin.map.tasks一起使用,执行细粒度的控制。

(3)桶Map连接

如果连接中使用的表是按特定列分桶的,可以开启桶Map连接提升性能。

<property> <name>hive.optimize.bucketmapjoin</name> 
<value>true</value>
</property> 
<property>
<name>hive.optimize.bucketmapjoin.sortedmerge</name>
<value>true</value> 
</property>

说明:

hive.optimize.bucketmapjoin:是否尝试桶Map连接。

hive.optimize.bucketmapjoin.sortedmerge:是否尝试在Map连接中使用归并排序。

3.避免使用order by全局排序

Hive中使用order by子句实现全局排序。order by只用一个Reducer产生结果,对于大数据集,这种做法效率很低。如果不需要全局有序,则可以使用sort by子句,该子句 为每个reducer生成一个排好序的文件。如果需要控制一个特定数据行流向哪个reducer,可以使用distribute by子句,例如:

select
id, name, salary, dept from
employee 
distribute by
dept sort by
id asc
, name desc
;

属于一个dept的数据会分配到同一个reducer进行处理,同一个dept的所有记录按照id、name列排序。最终的结果集是全局有序的。

4.启用Tez执行引擎

使用Tez执行引擎代替传统的MapReduce引擎会大幅提升Hive查询的性能。在安装好Tez后,配置hive.execution.engine属性指定执行引擎。

<property> 
<name>hive.execution.engine</name> 
<value>tez</value>
<description>
Expects one of [mr, tez, spark].
Chooses execution engine. Options are:
mr (Map reduce, default), tez (hadoop 2 only), spark
</description> 
</property>

5.优化limit操作

默认时limit操作仍然会执行整个查询,然后返回限定的行数。在有些情况下这种处理方式很浪费,因此可以通过设置下面的属性避免此行为。

<property> <name>hive.limit.optimize.enable</name> 
<value>true</value>
</property> <property>
<name>hive.limit.row.max.size</name>
<value>100000</value>
 </property>
<property> <name>hive.limit.optimize.limit.file</name> 
<value>10</value>
</property>
 <property>
<name>hive.limit.optimize.fetch.max</name>
<value>50000</value> </property>

说明:

hive.limit.optimize.enable:是否启用limit优化。当使用limit语句时,对源数据进行抽样。

hive.limit.row.max.size:在使用limit做数据的子集查询时保证的最小行数据量。

hive.limit.optimize.limit.file:在使用limit做数据子集查询时,采样的最大文件数。

hive.limit.optimize.fetch.max:使用简单limit数据抽样时,允许的最大行数。

6.启用并行执行

每条HiveQL语句都被转化成一个或多个执行阶段,可能是一个MapReduce阶段、采样阶段、归并阶段、限制阶段等。默认时,Hive在任意时刻只能执行其中一个阶段。

如果组成一个特定作业的多个执行阶段是彼此独立的,那么它们可以并行执行,从而整个作业得以更快完成。通过设置下面的属性启用并行执行。

<property> <name>hive.exec.parallel</name> 
<value>true</value>
</property> 
<property>
<name>hive.exec.parallel.thread.number</name>
<value>8</value> 
</property>

说明:

hive.exec.parallel:是否并行执行作业。

hive.exec.parallel.thread.number:最多可以并行执行的作业数。

7.启用MapReduce严格模式

Hive提供了一个严格模式,可以防止用户执行那些可能产生负面影响的查询。通过设置下面的属性启用MapReduce严格模式。

<property> 
<name>hive.mapred.mode</name> 
<value>strict</value>
</property>

严格模式禁止3种类型的查询。

对于分区表,where子句中不包含分区字段过滤条件的查询语句不允许执行。 对于使用了order by子句的查询,要求必须使用limit子句,否则不允许执行。 限制笛卡尔积查询。

8.使用单一Reduce执行多个Group By

通过为group by操作开启单一reduce任务属性,可以将一个查询中的多个group by操作联合在一起发送给单一MapReduce作业。

<property> <name>hive.multigroupby.singlereducer</name> 
<value>true</value>
<description>
Whether to optimize multi group by query to generate single M/R job plan.
If the multi group by query has common group by keys, it will be optimized to generate single M/R job.
</description> 
</property>

9.控制并行Reduce任务

Hive通过将查询划分成一个或多个MapReduce任务达到并行的目的。确定最佳的mapper个数和reducer个数取决于多个变量,例如输入的数据量以及对这些数据执行的操 作类型等。如果有太多的mapper或reducer任务,会导致启动、调度和运行作业过程中产生过多的开销,而如果设置的数量太少,那么就可能没有充分利用好集群内在的并 行性。对于一个Hive查询,可以设置下面的属性来控制并行reduce任务的个数。

<property> 
<name>hive.exec.reducers.bytes.per.reducer</name> 
<value>256000000</value>
</property> 
<property>
<name>hive.exec.reducers.max</name>
<value>1009</value> 
</property>

说明:

hive.exec.reducers.bytes.per.reducer:每个reducer的字节数,默认值为256MB。Hive是按照输入的数据量大小来确定reducer个数的。例如,如果输入的数据是1GB,将 使用4个reducer。


hive.exec.reducers.max:将会使用的最大reducer个数。

10.启用向量化

向量化特性在Hive 0.13.1版本中被首次引入。通过查询执行向量化,使Hive从单行处理数据改为批量处理方式,具体来说是一次处理1024行而不是原来的每次只处理一

行,这大大提升了指令流水线和缓存的利用率,从而提高了表扫描、聚合、过滤和连接等操作的性能。可以设置下面的属性启用查询执行向量化。

<property> 
<name>hive.vectorized.execution.enabled</name> 
<value>true</value>
</property> 
<property>
<name>hive.vectorized.execution.reduce.enabled</name>
<value>true</value> 
</property>
<property> 
<name>hive.vectorized.execution.reduce.groupby.enabled</name> 
<value>true</value>
</property>

说明:

hive.vectorized.execution.enabled:如果该标志设置为true,则开启查询执行的向量模式,默认值为false。 hive.vectorized.execution.reduce.enabled:如果该标志设置为true,则开启查询执行reduce端的向量模式,默认值为true。 hive.vectorized.execution.reduce.groupby.enabled:如果该标志设置为true,则开启查询执行reduce端group by操作的向量模式,默认值为true。

11.启用基于成本的优化器

Hive 0.14版本开始提供基于成本优化器(CBO)特性。使用过Oracle数据库的读者对CBO一定不会陌生。与Oracle类似,Hive的CBO也可以根据查询成本制定执行计划,例如确定表连接的顺序、以何种方式执行连接、使用的并行度等。设置下面的属性启用基于成本优化器。在 hdp 中默认开启。

<property> 
<name>hive.cbo.enable</name> 
<value>true</value>
</property> 
<property>
<name>hive.compute.query.using.stats</name>
<value>true</value> 
</property>
<property> 
<name>hive.stats.fetch.partition.stats</name> 
<value>true</value>
</property> 
<property>
<name>hive.stats.fetch.column.stats</name>
<value>true</value> </property>

说明:

hive.cbo.enable:控制是否启用基于成本的优化器,默认值是true。Hive的CBO使用Apache Calcite框架实现。 hive.compute.query.using.stats:该属性的默认值为false。如果设置为true,Hive在执行某些查询时,例如select count(1),只利用元数据存储中保存的状态信息返回结果。 为了收集基本状态信息,需要将hive.stats.autogather属性配置为true。为了收集更多的状态信息,需要运行analyze table查询命令。

hive.stats.fetch.partition.stats:该属性的默认值为true。操作树中所标识的统计信息,需要分区级别的基本统计,如每个分区的行数、数据量大小和文件大小等。分区 统计信息从元数据存储中获取。如果存在很多分区,要为每个分区收集统计信息可能会消耗大量的资源。这个标志可被用于禁止从元数据存储中获取分区统计。当 该标志设置为false时,Hive从文件系统获取文件大小,并根据表结构估算行数。

hive.stats.fetch.column.stats:该属性的默认值为false。操作树中所标识的统计信息,需要列统计。列统计信息从元数据存储中获取。如果存在很多列,要为每个列收 集统计信息可能会消耗大量的资源。这个标志可被用于禁止从元数据存储中获取列统计。

可以使用HiveQL的analyze table语句收集一个表中所有列相关的基本统计信息,例如下面的语句收集sales_order_fact表的统计信息。

analyze table
sales_order_fact compute statistics
 for
columns; 

analyze table
sales_order_fact compute statistics 
for
columns order_number, customer_sk;

12.使用ORC文件格式

ORC文件格式可以有效提升Hive查询的性能。图由Hortonworks公司提供,显示了Hive不同文件格式的大小对比。

注:本文内容大部分来源于《Hadoop构建数据仓库实践》,感谢作者分享和提供解决方案。

发布了508 篇原创文章 · 获赞 613 · 访问量 201万+

猜你喜欢

转载自blog.csdn.net/high2011/article/details/86546971