Hive做为大数据平台举足轻重的框架,以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。sql
可是若是咱们只局限于会使用Hive,而不考虑性能问题,就难搭建出一个完美的数仓,因此Hive性能调优是咱们大数据从业者必须掌握的技能。本文将给你们讲解Hive性能调优的一些方法及技巧。数据库
本文首发于公众号:五分钟学大数据
当咱们发现一条SQL语句执行时间过长或者不合理时,咱们就要考虑对SQL进行优化,优化首先得进行问题排查,那么咱们能够经过哪些方式进行排查呢。性能优化
常用关系型数据库的同窗可能知道关系型数据库的优化的诀窍-看执行计划。 如Oracle数据库,它有多种类型的执行计划,经过多种执行计划的配合使用,能够看到根据统计信息推演的执行计划,即Oracle推断出来的未真正运行的执行计划;还能够看到实际执行任务的执行计划;可以观察到从数据读取到最终呈现的主要过程和中间的量化数据。能够说,在Oracle开发领域,掌握合适的环节,选用不一样的执行计划,SQL调优就不是一件难事。服务器
Hive中也有执行计划,可是Hive的执行计划都是预测的,这点不像Oracle和SQL Server有真实的计划,能够看到每一个阶段的处理数据、消耗的资源和处理的时间等量化数据。Hive提供的执行计划没有这些数据,这意味着虽然Hive的使用者知道整个SQL的执行逻辑,可是各阶段耗用的资源情况和整个SQL的执行瓶颈在哪里是不清楚的。网络
想要知道HiveSQL全部阶段的运行信息,能够查看YARN提供的日志。查看日志的连接,能够在每一个做业执行后,在控制台打印的信息中找到。以下图所示:数据结构
Hive提供的执行计划目前能够查看的信息有如下几种:并发
在查询语句的SQL前面加上关键字explain是查看执行计划的基本方法。 用explain打开的执行计划包含如下两部分:框架
Hive中的explain执行计划详解可看我以前写的这篇文章:jvm
注:使用explain查看执行计划是Hive性能调优中很是重要的一种方式,请务必掌握!
总结:Hive对SQL语句性能问题排查的方式:
为何都说性能优化这项工做是比较难的,由于一项技术的优化,必然是一项综合性的工做,它是多门技术的结合。咱们若是只局限于一种技术,那么确定作很差优化的。
下面将从多个彻底不一样的角度来介绍Hive优化的多样性,咱们先来一块儿感觉下。
SQL语句优化涉及到的内容太多,因篇幅有限,不能一一介绍到,因此就拿几个典型举例,让你们学到这种思想,之后遇到相似调优问题能够往这几个方面多思考下。
insert into table stu partition(tp) select s_age,max(s_birth) stat,'max' tp from stu_ori group by s_age union all insert into table stu partition(tp) select s_age,min(s_birth) stat,'min' tp from stu_ori group by s_age;
咱们简单分析上面的SQl语句,就是将每一个年龄的最大和最小的生日获取出来放到同一张表中,union all 先后的两个语句都是对同一张表按照s_age进行分组,而后分别取最大值和最小值。对同一张表相同的字段进行两次分组,这形成了极大浪费,咱们能不能改造下呢,固然是能够的,为你们介绍一个语法:from ... insert into ...
,这个语法将from前置,做用就是使用一张表,能够进行屡次插入操做:
--开启动态分区 set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; from stu_ori insert into table stu partition(tp) select s_age,max(s_birth) stat,'max' tp group by s_age insert into table stu partition(tp) select s_age,min(s_birth) stat,'min' tp group by s_age;
上面的SQL就能够对stu_ori表的s_age字段分组一次而进行两次不一样的插入操做。
这个例子告诉咱们必定要多了解SQL语句,若是咱们不知道这种语法,必定不会想到这种方式的。
先看一个SQL,去重计数:
select count(1) from( select s_age from stu group by s_age ) b;
这是简单统计年龄的枚举值个数,为何不用distinct?
select count(distinct s_age) from stu;
有人说由于在数据量特别大的状况下使用第一种方式可以有效避免Reduce端的数据倾斜,可是事实如此吗?
咱们先无论数据量特别大这个问题,就当前的业务和环境下使用distinct必定会比上面那种子查询的方式效率高。缘由有如下几点:
hive.optimize.countdistinct
,即便真的出现数据倾斜也能够自动优化,自动改变SQL执行的逻辑。这个例子告诉咱们,有时候咱们不要过分优化,调优讲究适时调优,过早进行调优有可能作的是无用功甚至产生负效应,在调优上投入的工做成本和回报不成正比。调优须要遵循必定的原则。
Hive提供了多种数据存储组织格式,不一样格式对程序的运行效率也会有极大的影响。
Hive提供的格式有TEXT、SequenceFile、RCFile、ORC和Parquet等。
SequenceFile是一个二进制key/value对结构的平面文件,在早期的Hadoop平台上被普遍用于MapReduce输出/输出格式,以及做为数据存储格式。
Parquet是一种列式数据存储格式,能够兼容多种计算引擎,如MapRedcue和Spark等,对多层嵌套的数据结构提供了良好的性能支持,是目前Hive生产环境中数据存储的主流选择之一。
ORC优化是对RCFile的一种优化,它提供了一种高效的方式来存储Hive数据,同时也可以提升Hive的读取、写入和处理数据的性能,可以兼容多种计算引擎。事实上,在实际的生产环境中,ORC已经成为了Hive在数据存储上的主流选择之一。
咱们使用一样数据及SQL语句,只是数据存储格式不一样,获得以下执行时长:
数据格式 | CPU时间 | 用户等待耗时 |
---|---|---|
TextFile | 33分 | 171秒 |
SequenceFile | 38分 | 162秒 |
Parquet | 2分22秒 | 50秒 |
ORC | 1分52秒 | 56秒 |
注: CPU时间:表示运行程序所占用服务器CPU资源的时间。
*用户等待耗时*:记录的是用户从提交做业到返回结果期间用户等待的全部时间。
查询TextFile类型的数据表耗时33分钟, 查询ORC类型的表耗时1分52秒,时间得以极大缩短,可见不一样的数据存储格式也能给HiveSQL性能带来极大的影响。
小文件若是过多,对 hive 来讲,在进行查询时,每一个小文件都会当成一个块,启动一个Map任务来完成,而一个Map任务启动和初始化的时间远远大于逻辑处理的时间,就会形成很大的资源浪费。并且,同时可执行的Map数量是受限的。
因此咱们有必要对小文件过多进行优化,关于小文件过多的解决的办法,我以前专门写了一篇文章讲解,具体可查看:
Hive会将一个查询转化成一个或者多个阶段。这样的阶段能够是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程当中可能须要的其余阶段。默认状况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并不是彻底互相依赖的,也就是说有些阶段是能够并行执行的,这样可能使得整个job的执行时间缩短。若是有更多的阶段能够并行执行,那么job可能就越快完成。
经过设置参数hive.exec.parallel值为true,就能够开启并发执行。在共享集群中,须要注意下,若是job中并行阶段增多,那么集群利用率就会增长。
set hive.exec.parallel=true; //打开任务并行执行 set hive.exec.parallel.thread.number=16; //同一个sql容许最大并行度,默认为8。
固然得是在系统资源比较空闲的时候才有优点,不然没资源,并行也起不来。
JVM重用是Hadoop调优参数的内容,其对Hive的性能具备很是大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
Hadoop的默认配置一般是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会形成至关大的开销,尤为是执行的job包含有成百上千task任务的状况。JVM重用可使得JVM实例在同一个job中从新使用N次。N的值能够在Hadoop的mapred-site.xml
文件中进行配置。一般在10-20之间,具体多少须要根据具体业务场景测试得出。
<property> <name>mapreduce.job.jvm.numtasks</name> <value>10</value> <description>How many tasks to run per jvm. If set to -1, there is no limit. </description> </property>
咱们也能够在hive中设置
set mapred.job.reuse.jvm.num.tasks=10; //这个设置来设置咱们的jvm重用
这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。若是某个“不平衡的”job中有某几个reduce task执行的时间要比其余Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却没法被其余的job使用,直到全部的task都结束了才会释放。
在分布式集群环境下,由于程序Bug(包括Hadoop自己的bug),负载不均衡或者资源分布不均等缘由,会形成同一个做业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其余任务(好比一个做业的某个任务进度只有50%,而其余全部任务已经运行完毕),则这些任务会拖慢做业的总体执行进度。为了不这种状况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据必定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最早成功运行完成任务的计算结果做为最终结果。
设置开启推测执行参数:Hadoop的mapred-site.xml
文件中进行配置:
<property> <name>mapreduce.map.speculative</name> <value>true</value> <description>If true, then multiple instances of some map tasks may be executed in parallel.</description> </property> <property> <name>mapreduce.reduce.speculative</name> <value>true</value> <description>If true, then multiple instances of some reduce tasks may be executed in parallel.</description> </property>
hive自己也提供了配置项来控制reduce-side的推测执行:
set hive.mapred.reduce.tasks.speculative.execution=true
关于调优这些推测执行变量,还很难给一个具体的建议。若是用户对于运行时的误差很是敏感的话,那么能够将这些功能关闭掉。若是用户由于输入数据量很大而须要执行长时间的map或者Reduce task的话,那么启动推测执行形成的浪费是很是巨大大。
公众号【五分钟学大数据】,大数据领域原创技术号
代码优化原则: