hive优化

#优化设计:
考虑点:
1.模型设计(分区表,桶表)
2.文件格式(按机房配置,和实际需求选择)
3.数据倾斜(主键的设计,null主键的转换,map端combiner,)
4.减少map的数量(输入前合并文件,输出合并文件)
5.并行job数(同步进行)
6.jvm重用(jvm的资源开销)
7.Hql语句(开启Fetch简单查询,减少job的数量)
8.推测执行
9.其他参数调节

##1.设置分区表

对于HIVE来说,利用分区来设计表总是必要的.分区提供了一种隔离数据和优化查询的遍历的方式,特别是面对日益增长的数据规模,设置符合逻辑的分区可以避免进行全表扫描,只需加载特定某些hdfs目录的数据文件.
设置分区时,需要考虑设置成分区的字段,按照时间分区一般而言是一个好的方案,其好处在于其实按照不同时间颗粒度来确定合适大小的数据积累量,随着时间的推移,分区数量的增长是匀称的,分区的大小也是均匀的,达观数据每日处理大量的用户日志,对于user_log来说,设置分区字段为天或者月是合理的,但是如果,以userid字段来建立动态分区,而userid的基数是非常大的,显然分区数目是会超过hive的默认设置而执行失败,如果相对userid进行hash,我们可以以userid进行分桶(bucket),根据userid 进行hash然后分发到桶中,相同hash值的userid会分发到同一个桶中,每个桶对应这一个单独的文件

桶表:
hive bucket 桶对于每一个表(table)或者分区,Hive可以进一步组织成桶。Hive也是针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。采用桶能够带来一些好处,比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。
hive中table可以拆分成partition,table和partition可以通过‘CLUSTERED BY ’进一步分bucket,bucket中的数据可以通过‘SORT BY’排序。

set hive.enforce.bucketing = true;

总结点:
1.优化查询,这是分区(月或者日)
2.设置分桶(在分区的进一步分化)
PS:设置桶的作用
1.方便抽样查询
2.相同列表的通的两个表,join数据加快

##2.避免小文件

虽然分区有利于隔离数据和查询,设置过多过细的分区也会带来瓶颈,主要是因为HDFS非常容易存储大数据文件,由于分区对应着HDFS的目录结构,当存在过多的分区时,意味着文件的数目就越多,过多增长的小文件会给namenode带来巨大的性能压力,同时小文件过多会影响job的执行,hadoop会将一个job转换成多个task,即使对于每个小文件也需要要一个task去单独处理,task作为一个独立的jvm实例,其开启和停止的开销可能会大大超过实际的任务处理时间,因此,hive表设计分区不应该过多过细,每个目录下的文件足够大,应该是文件系统中块大小的若干倍

总结点:

1.影响namenode性能压力(元信息管理)
2.一个文件>一个map>一个task>一个jvm

处理方案:

1. jvm重用

小文件多或task多的业务场景
    set mapred.job.reuse.jvm.num.task=10  
    --开启10个task(jvm一直开着,应用场景,小文件,避免启动时间)

2.执行任务前合并小文件

Map合并小文件:

 set mapred.max.split.size=256000000 
  #每个Map最大输入大小(单位:字节)  
 set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat  
 #执行Map前进行小文件合并
  

输出合并(防止生成小文件):
 set hive.merge.mapfiles= true                 
 #在Map-only的任务结束时合并小文件  
 sethive.merge.mapredfiles= true               
 #在Map-Reduce的任务结束时合并小文件  
 set hive.merge.size.per.task= 256*1000*1000   
 #合并文件的大小  
 set hive.merge.smallfiles.avgsize=16000000     
 #当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge  

##3 选择文件格式

1.textfile

 textfile为默认格式
 存储方式:行存储
 优点,加载数据快(查询快)
 缺点:磁盘开销大,数据解析开销大
 压缩的text文件hive无法进行合并和拆分

2.sequencefile

二进制文件,以<key,value>的形式序列化到文件中
存储方式:行存储
优点:可分割,压缩,一般选择block压缩,查询中
缺点:存储空间最大,

3.rcfile(不用看)

存储方式:数据按行分块,每块按照列存储
压缩快,快速列存储
读记录尽量涉及到block最少
读取需要的列只需要读取每个row group的头部定义
读取全量数据的操作,性能比sequencefile没有明显的优势

4.orc(效率比rcfile高,是rcfile的改良版)

存储方式,数据按行分块,每块按照列存储
优点:压缩快,快速列存储,查询效率最高,列存储,避免扫描不必要的列读取
缺点:需要通过textfile文件转化

总结点:

TextFile: 好处,直接使用,加载数据快,坏处,磁盘开销大(无所顾忌)
orc: 好处,节省空间(存储空间是testfile的1/5),加载数据块,需要转换
text,seqfile能不用就尽量不要用  最好是选择orc

##4 group by 语句

ps:group by (id),有多少个id,就生成相应数量的reduce个数

案列分析:
对user_read_log表按userid group by 语句来继续探讨数据倾斜问题,首先我们explain group by 语句:
explain select userid,count(*) from user_read_log group by userid
Group By 的执行计划按照userid的hash值分发记录,同时在map端也做了本地reduce,groupby的shuffle 过程是按照hash(userid)来分发的,实际应用中日志中很多用户都是未注册用户或者未登陆,userid 字段为空的记录数远远大于userid不为空的记录数,当所有的空userid记录都分发到特定某一个reducer,对于groupby造成的数据倾斜问题,我们可以通过设置参数

  1. set hive.map.aggr=true (开启map端combiner);  
  2. set hive.groupby.skewindata=true(map端的key值随机分发); 

这个参数的作用是做reduce操作的时候,拿到的key并不是所有相同值的同一个reduce,而是随机分发,然后reduce做聚合,做完之后再做一轮MR,拿前面聚合过的数据再计算结果,虽然多了一轮MR任务,但是可以有效的见识数据倾斜问题可能带来的危险

ps:
1.每个文件至少产生一个map(按默认值128m算)
2.130m则产生两个map
3.combiner,(同机器上)map端做MR,然后再(不同机器上)reduce(多个机器上的map)

##5.Hive解决数据倾斜

正确的设置hive的参数可以在某种程度上避免数据倾斜问题,合适的查询语句,也可以避免数据倾斜问题,要尽早的过滤数据和裁剪数据,减少后续处理的数据量,是的join key 的数据分布较为均匀,将空字段随机赋予值,这样既可以均匀分发倾斜的数据

select userid,name from userid_info a
join (
select case when userid is null then cast(rand(47)*100000 as int)
else userid
from user_read_log
) b on (a.userid = b.userid)

select userid,name from userid_info a
join (
select userid
from user_read_log
where userid is not null
) b on (a.userid = b.userid)

##6.开启并发执行
同一个sql中的不同的job是否可以同时运行,提高作业的并发
set hive.exec.parallel=true
set hive.exec.parallel.thread.number = 32 (默认是8)

##零碎点:

  1. 将大表放后头,小表在前
    join连接时的优化:当多个表进行查询时,从左到右表的大小顺序应该是从小到大。原因:hive在对每行记录操作时会把其他表先缓存起来,直到扫描最后的表进行计算

  2. 使用相同的连接键( 减少job数)
    当对3个或者更多个表进行join连接时,如果每个on子句都使用相同的连接键的话,那么只会产生一个MapReduce job。

  3. 尽量尽早地过滤数据
    减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段。

select ... from 
A
join B
on A.key = B.key
where A.userid>10  
and B.userid<10
and A.dt='20120417'
and B.dt='20120417';

应该改写为:
select .... from 
(select .... from A where dt='201200417' and userid>10) a 
join ( select .... from B where dt='201200417'and userid < 10 ) b
on a.key = b.key;

4.order by & sort by (应避免排序操作)
sort by : 局部排序,并非全局有序,提高效率。
order by : 对查询结果进行全局排序,消耗时间长。

使用distribute by + sort by代替 order by

select * from baidu_click order by click desc;
select * from baidu_click distribute by product_line sort by click desc;

distribute by + sort by就是该替代方案,被distribute by设定的字段为KEY,数据会被HASH分发到不同的reducer机器上,然后sort by会对同一个reducer机器上的每组数据进行局部排序。

5.数据倾斜时负载均衡,当选项设定为true
set hive.map.aggr=true
set hive.groupby.mapaggr.checkinterval=1000000(用于设定map端进行聚合操作的条目数)
set hive.groupby.skewindata=true(map端key值随机分发)

有数据倾斜时进行负载均衡
  此处需要设定 hive.groupby.skewindata,当选项设定为 true 是,生成的查询计划有两个MapReduce 任务。
    在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个reduce 做部分聚合操作,并输出结果。这样处理的结果是,相同的 Group By Key 有可能分发到不同的 reduce 中,从而达到负载均衡的目的;
    第二个 MapReduce 任务再根据预处 理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作。

6.尽量避免执行MapReduce,简单查询(*,limit)直接通过Fetch task获取数据
ps:
1.set hive.fetch.task.conversion=more开启了Fetch任务 2.默认开启,在hiverc中设置初始化使用 3.在hive-site.xml中配置 <name>hive.fetch.task.conversion</name> <value>more</value>

##7.推测执行
(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;

##9.其他参数调节

9.1 USE VECTORIZATION
矢量查询(Vectorized query) 每次处理数据时会将1024行数据组成一个batch进行处理,而不是一行一行进行处理,这样能够显著提高执行速度。
可以通过设置

set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;

9.2 USE ORCFILE
ORCfile 使用了predicate push-down, compression等多种技术。Hive使用 ORCfile 作为表结构不仅可以节省存储空间,而且能够快速提高Hive Query的速度。

CREATE TABLE A_ORC (
    customerID int, 
    name string, 
    age int, 
    address string
) STORED AS ORC tblproperties (“orc.compress" = “SNAPPY”);

9.3 提交到任务队列

set mapreduce.job.queuename=root.online;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值