12.大数据之Hive性能优化

hive性能调优

1HADOOP计算框架特性

· 数据量大不是问题,数据倾斜是个问题。

· jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是map reduce作业初始化的时间是比较长的。

· sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题。

· count(distinct ),在数据量大的情况下,效率较低,如果是多count(distinct )效率更低,因为count(distinct)是按group by 字段分组,按distinct字段排序,一般这种分布方式是很倾斜的,比如男uv,女uv,淘宝一天30亿的pv,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。


2优化的常用手段 

· 好的模型设计事半功倍。

· 解决数据倾斜问题。

· 减少job数。

· 设置合理的map reducetask数,能有效提升性能。(比如,10w+级别的计算,用160reduce,那是相当的浪费,1个足够)

· 了解数据分布,自己动手解决数据倾斜问题是个不错的选择。set hive.groupby.skewindata=true;这是通用的算法优化,但算法优化有时不能适应特定业务背景,开发人员了解业务,了解数据,可以通过业务逻辑精确有效的解决数据倾斜问题。

· 数据量较大的情况下,慎用count(distinct)count(distinct)容易产生倾斜问题。

扫描二维码关注公众号,回复: 1543469 查看本文章

· 对小文件进行合并,是行至有效的提高调度效率的方法,假如所有的作业设置合理的文件数,对云梯的整体调度效率也会产生积极的正向影响。

· 优化时把握整体,单个作业最优不如整体最优。

    

3:全排序

Hive的排序关键字是SORT BY,它有意区别于传统数据库的ORDER BY也是为了强调两者的区别–SORT BY只能在单机范围内排序。

   order by  以及 sort by  distribute by   cluster by

   order by 语句  和数据库中的一样 会对结果集执行一个全局排序 但是  如果是全局排序的话  那么所有的数据 必须通过

   一个reduce进行处理  就是说 用Order by 必须保证只有一个reduce  任何情况下  都不会出现多个reduce  那么 程序

   运行的性能就会下降  非常容易出现数据倾斜的问题


   体会一下:

     set  mapred.reduce.tasks = 3;

     select  count(*) from emp group by deptno; 用了3reduce

     select ename,sal from emp order by sal desc;

     

     总结一下  什么情况下 我们不管如何设置reduce的个数  但他总是1  

     1. order by

     2. 没有group by 的汇总 比如 selct max(sal) from emp; 比如 select count(1) from emp;group by的汇总

     有几个group by的列 就要有几个reduce

     3.笛卡尔积   

     因为我们用order by只有一个reduce 非常容易出现数据倾斜 所以 如果我们添加了这个属性

     set hive.mapred.mode = strict;

     如果我们直接做排序 他不会让我们通过  select  * from emp order by sal desc;

     必须要加 Limit  select * from emp order by sal desc limit 5;


     sort  by

     sort byhive中独有的一个排序 它只会对每个reduce进行排序 也就是说  他执行的是一个局部排序

     也就是说  如果只有一个reduce  order by 效果一样  它只能保证每个reduce中的数据是有顺序的

     这样做  可以提高后面做全局排序的效率

     select sal from emp sort by sal desc;


    比如说 有这样一个需求 :

      我想要把每年的天气的前十名取出来  我们应该保证 每个reduce里面 都处理每一年的数据

      distribute by  相当于分区  保证 要distribute by的数据在同一个reduce中  要写在sort by的前面

      cluster by   distrbute by + sortby 的结合  但是  只支持 asc  不支持降序

 

4数据倾斜

4.1空值数据倾斜

场景:如日志中,常会有信息丢失的问题,比如全网日志中的user_id,如果取其中的user_idbmw_users关联,会碰到数据倾斜的问题。

解决方法1 user_id为空的不参与关联

Select * From log a

Join bmw_users b

On a.user_id is not null

And a.user_id = b.user_id

Union all

Select * from log a

where a.user_id is null;


解决方法2 赋与空值分新的key

Select *  

from log a 

left outer join bmw_users b 

on case when a.user_id is null then concat(‘dp_hive’,rand() ) else a.user_id end = b.user_id; 


4.2不同数据类型关联产生数据倾斜

场景:一张表s8的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。s8的日志中有字符串商品id,也有数字的商品id,类型是string的,但商品中的数字id是bigint的。猜测问题的原因是把s8的商品id转成数字id做hash来分配reduce,所以字符串id的s8日志,都到一个reduce上了,解决的方法验证了这个猜测。


解决方法:把数字类型转换成字符串类型

Select * from s8_log a

Left outer join r_auction_auctions b

On a.auction_id = cast(b.auction_id as string);


4.3大表Join的数据偏斜

MapReduce编程模型下开发代码需要考虑数据偏斜的问题,Hive代码也是一样。数据偏斜的原因包括以下两点:

1. Map输出key数量极少,导致reduce端退化为单机作业。

2. Map输出key分布不均,少量key对应大量value,导致reduce端单机瓶颈。


Hive中我们使用MapJoin解决数据偏斜的问题,即将其中的某个表(全量)分发到所有Map端进行Join,从而避免了reduce。这要求分发的表可以被全量载入内存。

极限情况下,Join两边的表都是大表,就无法使用MapJoin

这种问题最为棘手,目前已知的解决思路有两种:

1. 如果是上述情况1,考虑先对Join中的一个表去重,以此结果过滤无用信息。这样一般会将其中一个大表转化为小表,再使用MapJoin 

一个实例是广告投放效果分析,例如将广告投放者信息表i中的信息填充到广告曝光日志表w中,使用投放者id关联。因为实际广告投放者数量很少(但是投放者信息表i很大),因此可以考虑先在w表中去重查询所有实际广告投放者id列表,以此Join过滤表i,这一结果必然是一个小表,就可以使用MapJoin

 

2. 如果是上述情况2,考虑切分Join中的一个表为多片,以便将切片全部载入内存,然后采用多次MapJoin得到结果。

一个实例是商品浏览日志分析,例如将商品信息表i中的信息填充到商品浏览日志表w中,使用商品id关联。但是某些热卖商品浏览量很大,造成数据偏斜。例如,以下语句实现了一个inner join逻辑,将商品信息表拆分成2个表:

select * from

(

select w.id, w.time, w.amount, i1.name, i1.loc, i1.cat

from w left outer join i sampletable(1 out of 2 on id) i1

)

union all

(

select w.id, w.time, w.amount, i2.name, i2.loc, i2.cat

from w left outer join i sampletable(1 out of 2 on id) i2

)

);


以下语句实现了left outer join逻辑:

select t1.id, t1.time, t1.amount,

    coalease(t1.name, t2.name),

    coalease(t1.loc, t2.loc),

    coalease(t1.cat, t2.cat)

from (  

    select w.id, w.time, w.amount, i1.name, i1.loc, i1.cat

    from w left outer join i sampletable(1 out of 2 on id) i1

) t1 left outer join i sampletable(2 out of 2 on id) t2;

上述语句使用Hivesample table特性对表做切分。

 

5合并小文件

文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:

hive.merge.mapfiles = true 是否和并 Map 输出文件,默认为 True

hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False

hive.merge.size.per.task = 256*1000*1000 合并文件的大小

 

6Group By 

· Map 端部分聚合:

     并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果。

      基于 Hash

      参数包括:

§ hive.map.aggr = true 是否在 Map 端进行聚合,默认为 True

§ hive.groupby.mapaggr.checkinterval = 100000  Map 端进行聚合操作的条目数目


· 有数据倾斜的时候进行负载均衡

      hive.groupby.skewindata = false 

     当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

 

1.limit限制调整

--因为使用limit语句时候,是先执行整个查询语句,然后再返回部分结果的

set hive.limit.optimize.enable=true;

set hive.limit.row.max.size=10000;

set hive.limit.optimize.limit.file=10;

 

2.JOIN优化

。。。

 

3. 本地模式

--hive尝试使用本地模式执行查询,要不然hive会使用MapReduce来执行其他所有的查询

set hive.exec.mode.local.auto=true;

 

4.并行执行

set hive.exec.parallel=true;

 

5.严格模式

--对分区表进行查询,在where子句中没有加分区过滤的话,将禁止提交任务(默认:nonstrict)

set hive.mapred.mode=strict;

 

注:使用严格模式可以禁止3种类型的查询:

1)对于分区表,不加分区字段过滤条件,不能执行

2)对于order by语句,必须使用limit语句。

3)限制笛卡尔积的查询(join的时候不使用on,而使用where的)。

 

6.调整mapperreducer个数

set hive.exec.reducers.max=(集群总reduce槽位个数*1.5)/(执行中的查询的平均个数)

 

7.JVM重用

set mapred.job.reuse.jvm.num.tasks=10; --10为重用个数

 

8.索引

索引可以加快含有group by语句的查询的计算速度

 

9.动态分区调整

--动态分区属性:设置为true表示开启动态分区功能(默认为false

hive.exec.dynamic.partition=true;

 

--动态分区属性:设置为nonstrict,表示允许所有分区都是动态的(默认为strict

--设置为strict,表示必须保证至少有一个分区是静态的

hive.exec.dynamic.partition.mode=strict;

 

--动态分区属性:每个mapperreducer可以创建的最大动态分区个数

hive.exec.max.dynamic.partitions.pernode=100;

 

--动态分区属性:一个动态分区创建语句可以创建的最大动态分区个数

hive.exec.max.dynamic.partitions=1000;

 

--动态分区属性:全局可以创建的最大文件个数

hive.exec.max.created.files=100000;

 

--控制DataNode一次可以打开的文件个数

--这个参数必须设置在DataNode$HADOOP_HOME/conf/hdfs-site.xml文件中

<property>

    <name>dfs.datanode.max.xcievers</name>

    <value>8192</value>

</property>

 

10.推测执行

--目的:是通过加快获取单个task的结果以及进行侦测将执行慢的TaskTracker加入到黑名单的方式来提高整体的任务执行效率

 

1)修改 $HADOOP_HOME/conf/mapred-site.xml文件

         <property>

                   <name>mapred.map.tasks.speculative.execution </name>

                   <value>true</value>

         </property>

         <property>

                   <name>mapred.reduce.tasks.speculative.execution </name>

                   <value>true</value>

         </property>

 

2)修改hive配置

set hive.mapred.reduce.tasks.speculative.execution=true;

 

11.单个MapReduce中多个group by

--多个group by操作组装到单个MapReduce任务中

set hive.multigroupby.singlemr=false;

 

12.虚拟列

--hive产生了非预期的或null的时候,可以通过虚拟列进行诊断,判断哪行数据出现问题

INPUT__FILE__NAME  (输入文件名)

BLOCK__OFFSET__INSIDE__FILE  (块内偏移量)

ROW__OFFSET__INSIDE__BLOCK  (行偏移量,需要设置hive.exec.rowoffset=true;启用)

 

13. 其他参数调优

--开启CLI提示符前打印出当前所在的数据库名

set hive.cli.print.current.db=true;

 

--CLI打印出字段名称

hive.cli.print.header=true;

 

--提高聚合的性能

set hive.map.aggr=true;

 

--对于简单的不需要聚合的类似SELECT <col> from <table> LIMIT n语句,不需要起MapReduce job,直接通过Fetch task获取数据

set hive.fetch.task.conversion=more;

猜你喜欢

转载自blog.csdn.net/weixin_42217819/article/details/80561232
今日推荐