hive优化

来源:互联网 发布:化妆品好坏知多少阅读 编辑:程序博客网 时间:2024/06/06 10:43

优化设计:

考虑点:
模型设计(分区表,桶表)
文件格式(按机房配置,和实际需求选择)
数据倾斜(主键的设计,null主键的转换,map端combiner,)
减少job的数量(输入前合并文件,输出合并文件)
并行job数(同步进行)
jvm重用(jvm的资源开销)
Hql语句(开启Fetch简单查询,减少job的数量)

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.一个文件>一个job>一个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 Ajoin Bon A.key = B.keywhere A.userid>10  and B.userid<10and 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 ) bon a.key = b.key;

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

使用distribute by + sort by代替 order byselect * 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>

0 0