宁波电商网站建设开发,什么都能看的浏览器,使用flask做前后端分离的网站,android开发Hive作为大数据平台举足轻重的框架#xff0c;以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。
但是如果我们只局限于会使用Hive#xff0c;而不考虑性能问题#xff0c;就难搭建出一个完美的数仓#xff0c;所以Hive性能调优是我们大数据从业…Hive作为大数据平台举足轻重的框架以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。
但是如果我们只局限于会使用Hive而不考虑性能问题就难搭建出一个完美的数仓所以Hive性能调优是我们大数据从业者必须掌握的技能。本文将给大家讲解Hive性能调优的一些方法及技巧。
一、Hive性能调优的方式
为什么都说性能优化这项工作是比较难的因为一项技术的优化必然是一项综合性的工作它是多门技术的结合。我们如果只局限于一种技术那么肯定做不好优化的。
下面将从多个完全不同的角度来介绍Hive优化的多样性我们先来一起感受下。
1. SQL语句优化
SQL语句优化涉及到的内容太多因篇幅有限不能一一介绍到所以就拿几个典型举例让大家学到这种思想以后遇到类似调优问题可以往这几个方面多思考下。
1. union all
insert into table stu partition(tp)
select s_age,max(s_birth) stat,max tp
from stu_ori
group by s_ageunion allinsert 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.partitiontrue;
set hive.exec.dynamic.partition.modenonstrict; from stu_ori insert into table stu partition(tp)
select s_age,max(s_birth) stat,max tp
group by s_ageinsert into table stu partition(tp)
select s_age,min(s_birth) stat,min tp
group by s_age;上面的SQL就可以对stu_ori表的s_age字段分组一次而进行两次不同的插入操作。
这个例子告诉我们一定要多了解SQL语句如果我们不知道这种语法一定不会想到这种方式的。
2. distinct
先看一个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一定会比上面那种子查询的方式效率高。原因有以下几点 上面进行去重的字段是年龄字段要知道年龄的枚举值是非常有限的就算计算1岁到100岁之间的年龄s_age的最大枚举值才是100如果转化成MapReduce来解释的话在Map阶段每个Map会对s_age去重。由于s_age枚举值有限因而每个Map得到的s_age也有限最终得到reduce的数据量也就是map数量*s_age枚举值的个数。 distinct的命令会在内存中构建一个hashtable查找去重的时间复杂度是O(1)group by在不同版本间变动比较大有的版本会用构建hashtable的形式去重有的版本会通过排序的方式 排序最优时间复杂度无法到O(1)。另外第一种方式(group by)去重会转化为两个任务会消耗更多的磁盘网络I/O资源。 最新的Hive 3.0中新增了 count(distinct ) 优化通过配置 hive.optimize.countdistinct即使真的出现数据倾斜也可以自动优化自动改变SQL执行的逻辑。 第二种方式(distinct)比第一种方式(group by)代码简洁表达的意思简单明了如果没有特殊的问题代码简洁就是优
这个例子告诉我们有时候我们不要过度优化调优讲究适时调优过早进行调优有可能做的是无用功甚至产生负效应在调优上投入的工作成本和回报不成正比。调优需要遵循一定的原则。
2. 数据格式优化
Hive提供了多种数据存储组织格式不同格式对程序的运行效率也会有极大的影响。
Hive提供的格式有TEXT、SequenceFile、RCFile、ORC和Parquet等。
SequenceFile是一个二进制key/value对结构的平面文件在早期的Hadoop平台上被广泛用于MapReduce输出/输出格式以及作为数据存储格式。
Parquet是一种列式数据存储格式可以兼容多种计算引擎如MapRedcue和Spark等对多层嵌套的数据结构提供了良好的性能支持是目前Hive生产环境中数据存储的主流选择之一。
ORC优化是对RCFile的一种优化它提供了一种高效的方式来存储Hive数据同时也能够提高Hive的读取、写入和处理数据的性能能够兼容多种计算引擎。事实上在实际的生产环境中ORC已经成为了Hive在数据存储上的主流选择之一。
我们使用同样数据及SQL语句只是数据存储格式不同得到如下执行时长
数据格式CPU时间用户等待耗时TextFile33分171秒SequenceFile38分162秒Parquet2分22秒50秒ORC1分52秒56秒 注CPU时间表示运行程序所占用服务器CPU资源的时间。 用户等待耗时记录的是用户从提交作业到返回结果期间用户等待的所有时间。 查询TextFile类型的数据表CPU耗时33分钟 查询ORC类型的表耗时1分52秒时间得以极大缩短可见不同的数据存储格式也能给HiveSQL性能带来极大的影响。
3. 小文件过多优化
小文件如果过多对 hive 来说在进行查询时每个小文件都会当成一个块启动一个Map任务来完成而一个Map任务启动和初始化的时间远远大于逻辑处理的时间就会造成很大的资源浪费。而且同时可执行的Map数量是受限的。
所以我们有必要对小文件过多进行优化关于小文件过多的解决的办法我之前专门写了一篇文章讲解具体可查看
解决hive小文件过多问题
4. 并行执行优化
Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下Hive一次只会执行一个阶段。不过某个特定的job可能包含众多的阶段而这些阶段可能并非完全互相依赖的也就是说有些阶段是可以并行执行的这样可能使得整个job的执行时间缩短。如果有更多的阶段可以并行执行那么job可能就越快完成。
通过设置参数hive.exec.parallel值为true就可以开启并发执行。在共享集群中需要注意下如果job中并行阶段增多那么集群利用率就会增加。
set hive.exec.paralleltrue; //打开任务并行执行
set hive.exec.parallel.thread.number16; //同一个sql允许最大并行度默认为8。当然得是在系统资源比较空闲的时候才有优势否则没资源并行也起不来。
5. 数据倾斜优化
数据倾斜的原理都知道就是某一个或几个key占据了整个数据的90%这样整个任务的效率都会被这个key的处理拖慢同时也可能会因为相同的key会聚合到一起造成内存溢出。
Hive的数据倾斜一般的处理方案
常见的做法通过参数调优
set hive.map.aggrtrue;
set hive.groupby.skewindata ture;当选项设定为true时生成的查询计划有两个MapReduce任务。
在第一个MapReduce中map的输出结果集合会随机分布到reduce中每个reduce做部分聚合操作并输出结果。
这样处理的结果是相同的Group By Key有可能分发到不同的reduce中从而达到负载均衡的目的
第二个MapReduce任务再根据预处理的数据结果按照Group By Key分布到reduce中这个过程可以保证相同的Group By Key分布到同一个reduce中最后完成最终的聚合操作。
但是这个处理方案对于我们来说是个黑盒无法把控。
那么在日常需求的情况下如何处理这种数据倾斜的情况呢 sample采样获取哪些集中的key 将集中的key按照一定规则添加随机数 进行join由于打散了所以数据倾斜避免了 在处理结果中对之前的添加的随机数进行切分变成原始的数据。
例如发现有90%的key都是null数据量一旦过大必然出现数据倾斜可采用如下方式
SELECT *
FROM aLEFT JOIN b ON CASE WHEN a.user_id IS NULL THEN concat(hive_, rand())ELSE a.user_idEND b.user_id;注意给null值随机赋的值不要与表中已有的值重复不然会导致结果错误。
6. Limit 限制调整优化
一般情况下Limit语句还是需要执行整个查询语句然后再返回部分结果。
有一个配置属性可以开启避免这种情况对数据源进行抽样。
hive.limit.optimize.enabletrue -- 开启对数据源进行采样的功能
hive.limit.row.max.size -- 设置最小的采样容量
hive.limit.optimize.limit.file -- 设置最大的采样样本数
缺点有可能部分数据永远不会被处理到
7. JOIN优化
1. 使用相同的连接键
当对3个或者更多个表进行join连接时如果每个on子句都使用相同的连接键的话那么只会产生一个MapReduce job。
2. 尽量尽早地过滤数据
减少每个阶段的数据量,对于分区表要加分区同时只选择需要使用到的字段。
3. 尽量原子化操作
尽量避免一个SQL包含复杂逻辑可以使用中间表来完成复杂的逻辑。
8. 谓词下推优化
Hive中的 Predicate Pushdown 简称谓词下推简而言之就是在不影响结果的情况下尽量将过滤条件下推到join之前进行。谓词下推后过滤条件在map端执行减少了map端的输出降低了数据在集群上传输的量节约了集群的资源也提升了任务的性能。
我们看下面这个语句
select s1.key, s2.key
from s1 left join s2
on s1.key 2;上面是一个Left Join语句s1是左表称为保留行表s2是右表。
问on条件的s1.key 2 是在join之前执行还是之后也就是会不会进行谓词下推?
答不会进行谓词下推因为s1是保留行表过滤条件会在join之后执行。
而下面这个语句
select s1.key, s2.key
from s1 left join s2
on s2.key 2;s2表不是保留行所以s2.key2条件可以下推到s2表中也就是join之前执行。
再看下面这个语句
select s1.key, s2.key
from s1 left join s2
where s1.key 2;右表s2为NULL补充表。
s1不是NULL补充表所以s1.key2可以进行谓词下推。
而下面语句
select s1.key, s2.key
from s1 left join s2
where s2.key 2;由于s2为NULL补充表所以s2.key2过滤条件不能下推。
那么谓词下推的规则是什么到底什么时候会进行下推什么时候不会下推总结了下面的一张表建议收藏保存 案例
select a.*
from a
left join b on a.uid b.uid
where a.ds2020-08-10
and b.ds2020-08-10上面这个SQL主要犯了两个错误 右表(上方b表)的where条件写在join后面会导致先全表关联在过滤分区。 注虽然a表的where条件也写在join后面但是a表会进行谓词下推也就是先执行where条件再执行join但是b表不会进行谓词下推 on的条件没有过滤null值的情况如果两个数据表存在大批量null值的情况会造成数据倾斜。
二、最后
代码优化原则 理透需求原则这是优化的根本 把握数据全链路原则这是优化的脉络 坚持代码的简洁原则这让优化更加简单 没有瓶颈时谈论优化这是自寻烦恼。