前言:

最近刚触摸写Hive SQL,却发现许多查询的履行速度远不如预期。为了提升查询功率,我去阅读了《Hive编程攻略》,期望经过了解其底层机制来找到优化的方法,并为未来能编写出高效的SQL奠定根底。谨以此文做个记录。

一、Hive因何而生

先有Hadoop再有Hive

Hadoop完结了一个核算模型——MapReduce,它能够将核算使命分割成多个处理单元然后涣散到一群家用的或服务器级别的硬件机器上,然后下降核算成本并提供水平可伸缩性。可是这套编程模型关于大多数数据分析分析师较为杂乱和地销,即便是Java开发编写MapReduce程序也需求许多时间和精力。基于此,Hive提供了基于SQL的查询言语(HiveQL),这边能够让具有SQL知识的用户能够轻松运用Hadoop进行大数据分析,因为Hive的底层会自动将这些查询转换为MapReduce使命。

二、Hive组成模块

《Hive编程攻略》读书笔记

一切的指令和查询都会进入Driver,经过该模块对输入进行解析编译,对需求的核算进行优化,然后依照指定的进程履行。

Hive经过JobTracker通讯来初始化MapReduce使命,需求处理的数据文件是存储在HDFS中的,而HDFS是由NameNode进行办理的。

Metastore(元数据存储)是一个独立的联系型数据库,Hive会在其间保存表形式和其他系统元数据。

三、HQL履行流程

《Hive编程攻略》读书笔记

简单来说,Hive会从Hadoop散布式文件系统(HDFS)中读取原始数据,然后依据查询界说,在单节点(本地形式)或许Hadoop集群上(集群形式)履行数据处理。处理完结后,Hive会将结果输出到HDFS或许其他指定的存储位置。

那么,Hive的履行时间首要花费在哪儿呢?咱们可优化的部分是哪部分?

Hive的履行时间首要花费在以下几个阶段:

1.查询编译:Hive 将 HiveQL 查询编译成一个逻辑履行方案,这个方案描绘了如何履行查询。此阶段包括语法分析、语义分析、生成逻辑方案、逻辑方案优化和生成物理方案(一般是 MapReduce 作业)。

2.使命调度:编译生成的 MapReduce 作业被提交到 Hadoop 集群的资源办理器(如 YARN),等待资源调度和作业履行。

3.数据读写:读取存储在 HDFS 上的数据以及写入最终结果到 HDFS,这个进程涉及很多的磁盘 I/O 操作,尤其是在处理很多数据集时。

4.MapReduce 作业履行:包括

1.Map 阶段:履行过滤、投影等操作;

2.Shuffle 阶段:Map 使命输出的中心数据在网络上传输并在 Reduce 节点上进行排序和兼并;

3.Reduce 阶段:履行聚合、排序等操作;

5.网络传输:在 MapReduce 的 Shuffle 阶段,中心数据需求在集群节点之间传输,这或许导致显著的网络推迟。

一般,MapReduce 作业的履行时间(尤其是 Shuffle 和 Reduce 阶段)以及数据的读写操作是 Hive 查询中最耗时的部分,也是咱们优化进程中首要重视的部分,接下来咱们看下有哪些常见的优化方法。

四、Hive常见的优化方法

本地形式

-- 敞开本地形式,默以为false
hive.exec.mode.local.auto=true
原理:有时Hive的输入数据量是十分小的。在这种状况下,为查询触发履行使命的时间耗费或许会比实践job的履行时间要多得多。关于大多数这种状况,Hive能够经过本地形式在单台机器上处理一切的使命。关于小数据集,履行时间能够显着被缩短。用户能够经过设计特色
hive.exec.mode.local.auto的值为true,来让Hive在恰当的时分自动发动这个优化。实践有效,但假如并行履行的SQL过多,简单形成本地内存溢出。

map-side JOIN优化

#-- Hive v0.7之前需求经过增加符号 /*  MAPJOIN(X) */ 触发,如下图

《Hive编程攻略》读书笔记

-- Hive v0.7版别开端之后,经过设置hive.auto.convert.JOIN的值为true敞开
set hive.auto.convert.JOIN=true
-- 设置小表的大下,单位为字节
set hive.mapjoin.smalltable.filesize=25000000
原理:假如一切表中有一个表足够得小,是能够完结载入内存中的,那么这时Hive能够履行一个map-side JOIN,将小表彻底放到内存,Hive便能够直接和内存中的小表进行逐个匹配,然后削减所需求的reduce进程,有时甚至能够削减某些map task使命。

并发履行

-- 经过设置参数hive.exec.parallel值为true,敞开并发履行,默以为false
set hive.exec.parallel=true
原理:Hive会将一个查询转化成一个或许多个阶段。这样的阶段能够是MapReduce阶段、抽样阶段、兼并阶段、limit阶段等。默许状况下,Hive一次只会履行一个阶段。可是有些阶段并非彻底相互依靠的,也就是说这些阶段是能够并行履行的,这样能够使得整个job的履行时间缩短。
经过设置参数hive.exec.parallel值为true,就能够敞开并发履行。 

动态分区调整

-- 启用动态分区,默以为false;
SET hive.exec.dynamic.partition=true;
-- 启用动态分区形式为非严格形式。敞开严格形式时们必须确保至少有一个分区时静态的。
SET hive.exec.dynamic.partition.mode=nonstrict;
-- 设置在一个动态分区刺进操作中能够创立的最大分区数量
SET hive.exec.max.dynamic.partitions=1000;
-- 设置每个节点能够创立的最大分区数量
SET hive.exec.max.dynamic.partitions.pernode=100;
当履行查询时,假如查询条件包括分区键,Hive能够仅扫描相关分区的数据,然后削减了扫描的数据量,提高查询功率;在履行动态分区的刺进时,这些分区也能够并行写入,然后提高了数据写入的并行度和功能。经过以上参数,可更好的运用动态分区。

兼并小文件

--是否和并Map输出文件,默许true
SET hive.merge.mapfiles=true;
--是否兼并 Reduce 输出文件,默许false
SET hive.merge.mapredfiles=true;
-- 设置兼并文件的巨细阈值
SET hive.merge.size.per.task=256000000; 
-- 设置小文件的均匀巨细阈值
SET hive.merge.smallfiles.avgsize=128000000; 
因为一些小批量的写入、MapReduce作业切开、数据歪斜等原因,Hive中或许会发生很多小文件,经过以上参数可进行小文件兼并以削减读取文件时的开销、下降NameNode压力,提升查询功率。

数据歪斜优化

数据歪斜指的是在散布式处理进程中,数据不均匀地分配给各个节点处理,导致部分节点负载过重,而其他节点负载轻松,然后影响全体核算功率。数据歪斜出现的原因首要如下:

1.键值散布不均匀:有些键值对应的数据远多于其他键值;

2.量相同键值:很多数据运用相同的键(如null或许特定的默许值)进行分组;

3.不合理的JOIN操作:在JOIN大表时,假如小表的某个键值在大表中散布不均,导致JOIN后的结果歪斜;

4.不合理的分区战略:数据分区时没有考虑数据的实践散布,导致分区不均匀。

首要解决方案有:

1.自界说分区战略:完结自界说分区期,依据数据的特色进行更合理的分区;

2.扩展键值:对歪斜的键增加随机前缀或编号,使其涣散到多个分区;

3.过滤大键值数据:识别出歪斜的键值(如null、空值)进行单独处理或过滤掉不重要的数据。

最后就是咱们联系型数据库常用的优化方法相同也适用与Hive。例如经过运用小表关联大表的方法削减查询数据量,提高查询功率;Hive相同也有索引的概念,经过树立索引削减MapReduce的输入数据量,但相同和联系型数据库相同,是否运用索引需求进行仔细评价,因为维护索引也需求额定的存储空间,并且创立索引相同耗费核算资源;Hive相同也有EXPLAIN关键字,用于查询Hive时如何将查询转化为MapReduce使命的,运用EXPLAIN EXTENDED语句能够发生更多的输出信息,有爱好咱们可自行查看。

整体而言,这本书关于刚入门学习写HQL的我来说收获很大,让我初步对Hive有了基本的认知,也让我对我写的SQL有了更深化的了解。可是该书中的Hive应该版别比较低了,和咱们现在所运用的或许有所误差,不过入个门足够了。本文除了书中内容还有些我个人了解,如有过错,欢迎纠正。

作者: 马壮

来历:京东云开发者社区 转载请注明来历