Hive 性能优化 9 大技巧

  1. 使用 hint 来改写执行计划
select a.*, b.* 
from fctOrders a 
inner join employees b on a.employee_id = b.employee_id

显然 fctOrder 表的记录要比 employees 多上好几个数量级。将 fctOrders 放在第一位导致第一遍 map 跑批的数据量增大。因此当尽量用小表在 join 的左边。

有了 hint, 就不必在意 join 两表的顺序了:

select /*+ STREAMTABLE(a) */ a.*,b.*
from fctOrders a 
inner join employees b on a.employee_id = b.employee_id
  1. 使用配置来改写执行计划
set hive.auto.convert.join =true ;

select a.*, b.* 
from fctOrders a 
inner join employees b on a.employee_id = b.employee_id


同样是将 join 的两表进行位置互换,这一次是使用配置。

所有的配置需要固化下来,都可以放在 $HOME/.hiverc 文件中

  1. 使用 partition

针对大数据量的事实表做分区,比如按月做分区,那么查询每个月的基本数据量时,只需扫描单个分区即可,而不必要扫描整张大表。假设极限情况下,所有其他月的数据并不够多,而只是其中一个月的数据量很大,那么只有对这个月的数据进行有效分区之后,才能真正达到高效。

分区本质上还是分而治之,但如果分区数据并不是分布在每台集群中的服务器上,仅仅是存储在其中一台服务器上,分区也没有太大意义,在这种情况下就变成了单实例的数据库。除非分区在分布式集群中,也是均摊到各个集群节点服务器上。

3.1 如何去验证分区的数据,其实是分布在不同服务器上呢? namenode 查询,hdfs -ls.
3.2 如何对一张没有实现分区的表,做分区?一开始就没有实现分区的表,是不能直接在其上做分区的,必须新建同样结构的分区表,然后将数据导入
3.3 动态分区表如何实现?

  1. 使用 sequencefile 存储格式

当hdfs上的文件小于一个hdfs block的时候,被称作小文件。处理小文件并不是 hadoop 的专长,同样也不是 hive 的专长。

碰到这类问题,就需要将小文件统统归档到一个大文件里面去,比如 sequencefile.

比如 /user/hive/warehouse/logs 下面很多 10MB 的 log 文件,我们可以用 text file 来将整个目录下的文件都从逻辑上归档到一张表 temp_table 中去,再创建一张 sequenfile 表,将 temp_table中的数据装载到 sequencefile 中。

为什么不把这些数据重新插入一整张新表中去呢,这样依然可以满足大表的存储需求。

sequencefile 除了可以压缩功能,肯定还有其他特性吸引采用它,而不是其他文件存储格式。

  1. 使用 ORCfile 存储:

官方说明,predicate-push-down, compression 等技术使得 ORCfile 在 join 两张大表的时候,更能体现性能的优势。
来自 hortonworks 官方的说明, 对每张表都采用 ORCfile 格式存储,已经是个不争的技巧。

和 4 中的 sequencefile 格式比较,应该做一些例子来进行更严格的求证。

  1. 使用 Apache Tez 执行引擎

Tez 是基于 YARN 的一个计算引擎。配置 Tez 对于 Hive 有益的地方在于有效利用 YARN 带来的比 MapReduce 1 优异的性能。其中之一就是有效利用每台节点服务器的内存,防止浪费,也有效防止因数据得不到充足的内存而故障造成的任务延迟。

在最终的结果生成时,有效利用并行输出也是提高整体 HQL 的一环。

SET hive.tez.auto.reducer.parallelism=true;
  1. 使用 vectorization 技术
set hive.vectorized.execution.enabled=true ;
set hive.vectorized.execution.reduce.enabled=true;

在计算类似 scan, filter, aggregation 的时候, vectorization 技术以设置批处理的增量大小为 1024 行单次来达到比单条记录单次获得更高的效率。

是否 1024 行单次为固定的增量大小,是否可以设置更大的量?

  1. cost based query optimization

成本优化器:传统的数据库,成本优化器做出最优化的执行计划是依据统计信息来计算的。Hive 的成本优化器也一样。

set hive.cbo.enable = true ;
set hive.compute.query.using.stats = true ;
set hive.stats.fetch.column.stats = true ;
set hive.stats.fetch.partition.stats = true ;

以上开启了 cost based optimization.

下面的命令重新计算了统计信息:

analyze table tweets compute statistics;
analyze table tweents compute statistics for columns sender, topic;
analyze table tweens compute statistics for columns ;
  1. 语句级别的调优

比如: row_number 可以解决 Hive 级别的 Join 导致的网络传输速度慢的问题,但在 sql server 中就不能这么用了。

select tmp.* 
from (select a, row_number()over(partition by category order by orderDate desc) as rnk 
        from fctOrder
        ) tmp 
where rnk = 1
select a.* 
from fctOrder a 
inner join (select category,max(orderDate) as maxDate from fctOrder 
            group by category ) tmp on a.category = tmp.category 
                                    and a.orderDate = tmp.maxDate

这类应用在 sql server 和 Hive 中各自的效率是不一样的。

8.1 避免使用 SELECT COUNT(Distinct field) FROM tblTable

使用

SELECT COUNT(1) AS TotalCount
FROM (
        SELECT Distinct field
        FROM tblTable
    )Tmp

这里最重要的思想便是将所有的计算拆成利用多个 reducer 进行计算的模式,而不是将全部的计算都压到一个 reducer.

8.2 慎重考虑用于分组的笛卡尔运算:

good:SELECT GROUP BY userId, gender
bad: SELECT GROUP BY gender,userId

userId 在前面,可利用多个 reducer 进行分组运算,而 gender 则之多会应用 3 个 reduer. 一是男,二是女,三未知。

8.3 Each-Top-N 的求解

每组前 N 个的应用场景,在数据分析领域常用。在 SQL 中一般用窗口函数 Rank()Over(Partition By)来计算。

而 Hive 中为了更好的发挥分布式运算,需要利用多个 reducer 来处理。

SELECT *,Rank()Over(Partition BY)
FROM tblTable
Distribute By FieldA 
Sort By FieldA, MetricA DESC

这需要验证,Hive 中支持的 Window Function 有哪些要求。

  1. 使用 predicate pushdown (PPD) 在存储级别执行过滤
SET hive.optimize.ppd=true ;
SET hive.optimize.ppd.storage=true ;

你可能感兴趣的:(Hive)