HIVE SQL的简单优化

1.列裁剪

Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列,这样做节省了读取开销,中间表存储开销和数据整合开销

参数设置:

       hive.optimize.cp=true(默认值为真,该参数已被移除)

HIVE SQL的简单优化

 

2.分区剪裁可以在查询的过程中减少不必要的分区

在对分区表进行查询时,优化器会检查谓词条件中是否存在对分区字段的过滤,如果存在,则可以仅访问符合条件的分区

在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤

HIVE SQL的简单优化

分区参数为:hive.optimize.pruner=true(默认值为真)

 

3.group by

并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。

开启Map端聚合参数设置:

--(1)是否在Map端进行聚合,默认为True(开启)

set hive.map.aggr = true;

开启map端combiner。此配置可以group by语句中提高HiveQL聚合的执行性能。这个设置可以将顶层的聚合操作放在Map阶段执行,从而减轻数据传输和Reduce阶段的执行时间,提升总体性能。

 

--(2)在Map端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000;

 

--(3)有数据倾斜的时候进行负载均衡(默认是false,要启用时,将其设置为true)

set hive.groupby.skewindata = true;

这个配置项是用于决定group by操作是否支持倾斜数据的负载均衡处理,该变量设置为true,那么Hive会自动进行负载均衡

默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了

对于大数据量中,如果出现数据倾斜时,会使得性能非常差,解决办法为设置数据负载均衡,其设置方法为设置hive.groupby.skewindata参数

启用时,能够解决数据倾斜的问题,但如果要在查询语句中对多个字段进行去重统计时会报错

 

开启后:(多个列上进行的去重操作与hive环境变量hive.groupby.skewindata存在冲突)

---------select ip, count(distinct id),count(distinct x) from test group by ip; 会报如下错误:

FAILED: SemanticException [Error 10022]: DISTINCT on different columns not supported with skew in data

这样写是OK的: select ip,count(distinct id, x) from test group by ip

 

当选项设定为 true,生成的查询计划会有两个MR Job(执行完第一个MR Job再执行第二个MR Job)。

第一个MR Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是:相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;

第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。

 

4.count(distinct)

数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换:

count(distinct)吃内存,查询快;group by空间复杂度小,在时间复杂度允许的情况下,可以发挥他的空间复杂度优势。

 

如:

SELECT count(DISTINCT id) FROM bigtable;  ==> SELECT count(id) FROM (SELECT id FROM bigtable GROUP BY id) a;

HIVE SQL的简单优化

 

5.避免笛卡尔积

尽量避免笛卡尔积,即避免join的时候不加on条件,或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积。

 

动态分区调整

往hive分区表中插入数据时,hive提供了一个动态分区功能,其可以基于查询参数的位置去推断分区的名称,从而建立分区。使用Hive的动态分区,需要进行相应的配置。

开启动态分区功能(默认true,开启)

set hive.exec.dynamic.partition=true;

 

设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)

set hive.exec.dynamic.partition.mode=nonstrict;

 

在所有执行MR的节点上,最大一共可以创建多少个动态分区。

set  hive.exec.max.dynamic.partitions=1000;

 

在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。

set hive.exec.max.dynamic.partitions.pernode=100

 

整个MR Job中,最大可以创建多少个HDFS文件

在linux系统当中,每个linux用户最多可以开启1024个进程,每一个进程最多可以打开2048个文件,即持有2048个文件句柄,下面这个值越大,就可以打开文件句柄越大

set hive.exec.max.created.files=100000;

 

有空分区生成时,是否抛出异常。一般不需要设置。

set hive.error.on.empty.partition=false;