1.列裁剪
Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列,这样做节省了读取开销,中间表存储开销和数据整合开销
参数设置:
hive.optimize.cp=true(默认值为真,该参数已被移除)
2.分区剪裁可以在查询的过程中减少不必要的分区
在对分区表进行查询时,优化器会检查谓词条件中是否存在对分区字段的过滤,如果存在,则可以仅访问符合条件的分区
在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤
分区参数为: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;
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;