Hive优化

Hive优化可以通过以下来进行考虑

1、建立表分区

使用场景

Hive在做Select查询时,一般会扫描整个表内容,会消耗较多时间去扫描不关注的数据。此时,可根据业务需求及其查询维度,建立合理的表分区,从而提高查询效率。

指定静态分区或者动态分区

  • 静态分区:

静态分区是手动输入分区名称,在创建表时使用关键字PARTITIONED BY指定分区列名及数据类型。应用开发时,使用ALTER TABLE ADD PARTITION语句增加分区,以及使用LOAD DATA INTO PARTITON语句将数据加载到分区时,只能静态分区。

  • 动态分区:通过查询命令,将结果插入到某个表的分区时,可以使用动态分区。

动态分区通过在客户端工具执行如下命令来开启:

set hive.exec.dynamic.partition=true

动态分区默认模式是strict,也就是必须至少指定一列为静态分区,在静态分区下建立动态子分区,可以通过如下设置来开启完全的动态分区:

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

说明:

  1. 动态分区可能导致一个DML语句创建大量的分区,对应的创建大量新文件夹,对系统性能可能带来影响。
  2. 在文件数量大的情况下,执行一个SQL语句启动时间较长,可以在执行SQL语句之前执行“set mapreduce.input.fileinputformat.list-status.num-threads = 100;”语句来缩短启动时间。“mapreduce.input.fileinputformat.list-status.num-threads”参数需要先添加到Hive的白名单才可设置。     

2 Join优化

使用Join语句时,如果数据量大,可能造成命令执行速度和查询速度慢,此时可进行Join优化。

Join优化可分为以下方式:

  • Map Join
  • Sort Merge Bucket Map Join

Join顺序优化

 

Map Join

Hive的Map Join适用于能够在内存中存放下的小表(指表大小小于25MB),通过“hive.mapjoin.smalltable.filesize”定义小表的大小,默认为25MB。

Map Join的方法有两种:

  • 使用/*+ MAPJOIN(join_table) */。
  • 执行语句前设置如下参数,当前版本中该值默认为true。
set hive.auto.convert.join=true

使用Map Join时没有Reduce任务,而是在Map任务前起了一个MapReduce Local Task,这个Task通过TableScan读取小表内容到本机,在本机以HashTable的形式保存并写入硬盘上传到DFS,并在distributed cache中保存,在Map Task中从本地磁盘或者distributed cache中读取小表内容直接与大表join得到结果并输出。

使用Map Join时需要注意小表不能过大,如果小表将内存基本用尽,会使整个系统性能下降甚至出现内存溢出的异常。

 

Sort Merge Bucket Map Join

使用Sort Merge Bucket Map Join必须满足以下2个条件:

  1. join的两张表都很大,内存中无法存放。
  2. 两张表都按照join key进行分桶(clustered by (column))和排序(sorted by(column)),且两张表的分桶数正好是倍数关系。

通过如下设置,启用Sort Merge Bucket Map Join:

set hive.optimize.bucketmapjoin=true 
set hive.optimize.bucketmapjoin.sortedmerge=true

这种Map Join也没有Reduce任务,是在Map任务前启动MapReduce Local Task,将小表内容按桶读取到本地,在本机保存多个桶的HashTable备份并写入HDFS,并保存在Distributed Cache中,在Map Task中从本地磁盘或者Distributed Cache中按桶一个一个读取小表内容,然后与大表做匹配直接得到结果并输出。

 

Join顺序优化

当有3张及以上的表进行Join时,选择不同的Join顺序,执行时间存在较大差异。使用恰当的Join顺序可以有效缩短任务执行时间。

Join顺序原则:

  • Join出来结果较小的组合,例如表数据量小或两张表Join后产生结果较少,优先执行。
  • Join出来结果大的组合,例如表数据量大或两张表Join后产生结果较多,在后面执行。

例如,customer表的数据量最多,orders表和lineitem表优先Join可获得较少的中间结果。

原有的Join语句如下:

select
  l_orderkey,
  sum(l_extendedprice * (1 - l_discount)) as revenue,
  o_orderdate,
  o_shippriority
from
  customer,
  orders,
  lineitem
where
  c_mktsegment = 'BUILDING'
  and c_custkey = o_custkey
  and l_orderkey = o_orderkey
  and o_orderdate < '1995-03-22'
  and l_shipdate > '1995-03-22'
limit 10;

Join顺序优化后如下:

select
  l_orderkey,
  sum(l_extendedprice * (1 - l_discount)) as revenue,
  o_orderdate,
  o_shippriority
from
  orders,
  lineitem,
  customer
where
  c_mktsegment = 'BUILDING'
  and c_custkey = o_custkey
  and l_orderkey = o_orderkey
  and o_orderdate < '1995-03-22'
  and l_shipdate > '1995-03-22'
limit 10;

注意事项

Join数据倾斜问题

执行任务的时候,任务进度长时间维持在99%,这种现象叫数据倾斜。

数据倾斜是经常存在的,因为有少量的Reduce任务分配到的数据量和其他Reduce差异过大,导致大部分Reduce都已完成任务,但少量Reduce任务还没完成的情况。

解决数据倾斜的问题,可通过设置set hive.optimize.skewjoin=true并调整hive.skewjoin.key的大小。hive.skewjoin.key是指Reduce端接收到多少个key即认为数据是倾斜的,并自动分发到多个Reduce。

 

 3、Group By优化

优化Group by语句,可提升命令执行速度和查询速度。

Group by的时候, Map端会先进行分组, 分组完后分发到Reduce端, Reduce端再进行分组。可采用Map端聚合的方式来进行Group by优化,开启Map端初步聚合,减少Map的输出数据量。

在Hive客户端进行如下设置:

set hive.map.aggr=true

Group By数据倾斜

Group By也同样存在数据倾斜的问题,设置hive.groupby.skewindata为true,生成的查询计划会有两个MapReduce Job,第一个Job的Map输出结果会随机的分布到Reduce中,每个Reduce做聚合操作,并输出结果,这样的处理会使相同的Group By Key可能被分发到不同的Reduce中,从而达到负载均衡,第二个Job再根据预处理的结果按照Group By Key分发到Reduce中完成最终的聚合操作。

Count Distinct聚合问题

当使用聚合函数count distinct完成去重计数时,处理值为空的情况会使Reduce产生很严重的数据倾斜,可以将空值单独处理,如果是计算count distinct,可以通过where字句将该值排除掉,并在最后的count distinct结果中加1。如果还有其他计算,可以先将值为空的记录单独处理,再和其他计算结果合并。

4、 数据存储优化

 

“ORC”是一种高效的列存储格式,在压缩比和读取效率上优于其他文件格式。

建议使用“ORC”作为Hive表默认的存储格式。

操作步骤

  • 推荐:使用“SNAPPY”压缩,适用于压缩比和读取效率要求均衡场景。
Create table xx stored as orc tblproperties ("orc.compress"="SNAPPY")

 

  • 可用:使用“ZLIB”压缩,适用于压缩比要求较高场景。
Create table xx stored as orc tblproperties ("orc.compress"="ZLIB")

说明:xx为具体使用的Hive表名。

5、 SQL优化

在Hive上执行SQL语句查询时,如果语句中存在“(a&b) or (a&c)”逻辑时,建议将逻辑改为“a & (b or c)”。

例子:

假设条件a为“p_partkey = l_partkey”,优化前样例如下所示:

select
        sum(l_extendedprice* (1 - l_discount)) as revenue
from
        lineitem,
        part
where   
        (
                p_partkey = l_partkey 
                and p_brand = 'Brand#32'
                and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')
                and l_quantity >= 7 and l_quantity <= 7 + 10
                and p_size between 1 and 5
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        )
        or
        (       p_partkey = l_partkey 
                and p_brand = 'Brand#35'
                and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')
                and l_quantity >= 15 and l_quantity <= 15 + 10
                and p_size between 1 and 10
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        )
        or
        (       p_partkey = l_partkey 
                and p_brand = 'Brand#24'
                and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')
                and l_quantity >= 26 and l_quantity <= 26 + 10
                and p_size between 1 and 15
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        )

优化后样例如下所示:

select
        sum(l_extendedprice* (1 - l_discount)) as revenue
from
        lineitem,
        part
where   p_partkey = l_partkey and
        ((
                p_brand = 'Brand#32'
                and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')
                and l_quantity >= 7 and l_quantity <= 7 + 10
                and p_size between 1 and 5
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        )
        or
        (
                p_brand = 'Brand#35'
                and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')
                and l_quantity >= 15 and l_quantity <= 15 + 10
                and p_size between 1 and 10
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        )
        or
        (
                p_brand = 'Brand#24'
                and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')
                and l_quantity >= 26 and l_quantity <= 26 + 10
                and p_size between 1 and 15
                and l_shipmode in ('AIR', 'AIR REG')
                and l_shipinstruct = 'DELIVER IN PERSON'
        ))

6使用Hive CBO优化查询

在Hive中执行多表Join时,Hive支持开启CBO(Cost Based Optimization),系统会自动根据表的统计信息,例如数据量、文件数等,选出最优计划提高多表Join的效率。Hive需要先收集表的统计信息后才能使CBO正确的优化。

说明:

  • CBO优化器会基于统计信息和查询条件,尽可能地使join顺序达到最优。但是也可能存在特殊情况导致join顺序调整不准确。例如数据存在倾斜,以及查询条件值在表中不存在等场景,可能调整出非优化的join顺序。
  • 开启列统计信息自动收集时,需要在reduce侧做聚合统计。对于没有reduce阶段的insert任务,将会多出reduce阶段,用于收集统计信息。

操作步骤:

     1、在Manager界面Hive组件的服务配置中搜索“hive.cbo.enable”参数,选中“true”永久开启功能或者通过以下命令临时开启功能:

set hive.cbo.enable=true;

    2、手动收集Hive表已有数据的统计信息。

执行以下命令,可以手动收集统计信息。仅支持统计一张表,如果需要统计不同的表需重复执行。

ANALYZE TABLE [db_name.]tablename [PARTITION(partcol1[=val1], partcol2[=val2], ...)]
COMPUTE STATISTICS
[FOR COLUMNS]
[NOSCAN];
    • 指定FOR COLUMNS时,收集列级别的统计信息。
    • 指定NOSCAN时,将只统计文件大小和个数,不扫描具体文件。

例如:

analyze table table_name compute statistics;

analyze table table_name compute statistics for columns;

  1. 配置Hive自动收集统计信息。开启配置后,执行insert overwrite/into命令插入数据时才自动统计新数据的信息。
    • 在Hive客户端执行以下命令临时开启收集:
set hive.stats.autogather = true; 开启表/分区级别的统计信息自动收集。

set hive.stats.column.autogather = true; 开启列级别的统计信息自动收集。
  1. 列级别统计信息的收集不支持复杂的数据类型,例如Map,Struct等。
    • 表级别统计信息的自动收集不支持Hive on HBase表。
    • 在Manager界面Hive的服务配置中,搜索参数“hive.stats.autogather”和“hive.stats.column.autogather”,选中“true”永久开启收集功能。
  2. 执行以下命令可以查看统计信息。
DESCRIBE FORMATTED table_name[.column_name] PARTITION partition_spec;

例如:

desc formatted table_name;

desc formatted table_name.id;

desc formatted table_name.id partition(time='2016-05-27');

http://support.huawei.com/enterprise/product/images/e57648a0008a40ecbd3bb9f6be895034 说明:

分区表仅支持分区级别的统计信息收集,因此分区表需要指定分区来查询统计信息。

 

 

你可能感兴趣的:(hive)