[hive]hive优化

1.fetch抓取

1)什么是fetch抓取

fetch抓取是指hive对select 所有字段、select 指定字段、limit可以不必使用MapReduce计算,在这种情况下,hive可以简单地读取表对应的存储目录下的文件.

然后输出查询结果到控制台,这比走MR来说,大大减少了运行时间.

2)相关配置

hive.default.xml文件中hive.fetch.task.conversion默认是more.该属性设置为more以后,在全局查找,字段查找,limit查找等都不走mapreduce.

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
        值可以选择:[none,minimal,more]
        0. none:全部走MR
        1. minimal:部分走MR
        2. more:全局查找,字段查找,limit查找都不走MR
    </description>
</property>

2.本地模式

1)什么是本地模式

      大多数MR job是需要并行执行的,有时hive输入的数据量是非常小的,在这种情况下为触发任  务消耗的时间可能会比实际job的执行时间要多的多。此时执行hive本地模式,即在单台计算机上处理所有的任务。对于小的数据集,执行时间可能明显缩短。

2)相关配置

设置hive.exec.mode.local.auto的值为true,来让hive在适当的时候自动启动本地MR模式
set hive.exec.mode.local.auto=true;
设置本地MR的最大数据量,当输入数据量小于这个值时采用local MR模式,默认为128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
设置local MR的最大输入文件个数,当输入文件个数小于这个值时采用local MR模式,默认为4.
set hive.exec.mode.local.auto.input.files.max=10;

三表的优化

1.小表join大表

实际测试发现,新版的hive小表放在左边和右边已经没有明显区别。当执行map join时,小表join大表和大表join小表没有区别,会加载小表到大表的每个map端,在map端完成join.

以前是:前面的表都会被加载到内存中,后面的表进行磁盘扫描。

2.大表join大表

1)空key过滤

在mapreduce程序中,相同key对应的数据都会发送到相同的reduce task上。而所有值为Null的key都会被发送到同一个reduce task上,如果这样的数据太多,会导致内存不够。很多情况下,这些值为null的key对应的数据也是异常数据,我们可以直接把他们过滤掉。

2)空key转换 

有时,空key对应的数据不是异常数据,其数据必须要包括在join中,为了不让所有空key都对应的数据跑到相同的reduce task。出现数据倾斜,内存溢出等问题。我们可以给值为null的赋一个随机的值,使得其对应的数据可以随机且均匀分布在不同的reduce上。

下面这个sql表是t1中的id为null时不参与聚合,在join时,将它的key临时转为一个随机数,这样避免了分到一个reduce中.但是这个t1的id实际上没有个改变,只是join的时候用作key时变了.

select t1.*
from t1 full join t2
on case when t1.id is null then concat('hive',rand()) else t1.id end = t2.id;

3)SMB Join(重点)

SMB=sort merge bucket join

如何进行SMB join?

1.两表是分别以join on的条件建立的分桶表,且分的桶数相同.
2.set hive.optimize.bucketmapjoin=true;
  set hive.optimize.bucketmapjoin.sortedmerge=true;
  set hive.input.format=org.hadoop.hive.ql.io.BucketizedHiveInputFormat;

3.map join

1)common join

什么是common join?

如果不指定map join或者不符合map join的条件,那么hive解析器会将join操作转换成common join,即:在reduce阶段完成join. 整个过程包含:map、shuffle、reduce阶段。

①map阶段

读取源表的数据,在map端输出时,以join on条件作为key,如果join有多个关联键,则以这些关联键的组合作为key。map输出的value为join之后所关心的(select 或者 where中需要用到的)列。同时,在value中还包含表的tag信息,用于标明此value对应哪个表。

②shuffle阶段

将key-value按照key的hash值推送至不同的reduce中,这样确保两个表中相同的key位于同一个reduce中。

③reduce阶段

根据key的值完成join操作,期间通过tag来识别不同表的数据。

2)hive map join

①什么是map join?

就是在map阶段进行表之间的连接,而不是进入到reduce阶段才进行连接。这样就节省了在shuffle阶段时要进行的大量数据传输,从而起到了优化job的作用。

②map join的原理

通常情况下,相同key的key-value存在于不同的map task中。这样就必须在reduce task阶段连接。要使map task能够顺利进行,那么就必须满足这样的条件:只有一份表的数据分布在不同的map中,其他连接表的数据必须在该表的不同map中有完整的拷贝。

③map join使用的场景

在两个要连接的表中,有一个很大,有一个很小,这样这个小表可以存放在内存中而不影响性能。我们把小表的文件复制到那张大表的map task中,再让map把文件读到内存中待用。

④hive内置提供的优化机制之一就包括map join

在很久以前,这个选项就自动开启:默认小表25M

set hive.auto.convert.join=true;
hive还提供了另一个参数:表文件的大小作为开启和关闭map join的阈值.
hive.mapjoin.smalltable.filesize=25000000 即25M
当指定map join时,小表join大表和大表join小表没有区别。会加载小表到每个map端,在map端完成join。

4.join数据倾斜

set hive.skewjoin.key=100000; 默认为10万.
join的key对应的记录条数超过这个值则会进行拆分,值根据数据量设置
ste hive.optimize.skewjoin=false;
如果是join过程中出现数据清切应该设置为true;

如果开启了,在join的过程中会开启两个MR,通过下面的参数可以控制第二个job的mapper数量
set hive.skewjoin.mapjoin.map.tasks=10000;默认1万;

5.group by

①并不是所有的聚合操作都需要在reduce端完成,很多聚合操作可以先在map端进行预聚合,然后在reduce端得出最终结果。

hive.map.aggr=true;
是否在map端进行预聚合,默认为true
set hive.groupby.mapaggr.checkinterval=100000;
在map端进行聚合操作的条目数目

②hive.groupby.skewindata=true 注:skew倾斜

该方法在reduce端预聚合,聚合程度比map阶段预聚合程度高(因为map片多,个数多).
当选项设定为true,会有两个MR job。
在第一个MR job中,map的输出结果会随机分发到reduce中。每个reduce做部分聚合操作,
并输出结果。这样处理的结果是相同的group by key有可能被分发到不同的reduce中,从而
达到负载均衡的目的。
第二个MR job再根据预处理的数据结果按照group by key分布到一个reduce中(这个可以
保证相同的group by key被分到同一个reduce中)。最后完成最终的聚合操作。

6.count(distinct)去重

该操作在一个reduce task中执行,当数据量大的时候,这个reduce task需要处理的数据量太大,会导致整个job难以完成。用先group by id再count(id) 来替换。

7.笛卡尔积

应尽量避免笛卡尔积。因为只用一个reduce task执行笛卡尔积,出现笛卡尔积的情景:

1)select t1,t2

2)join时不加条件

8.行列过滤

列处理:在select中指定想要的列,尽量避免用select *

行处理:当使用left join、right join、full join时,如果将后面表的过的过滤写在where后面。就会先全表关联,之后再过滤。  

四.并行执行

什么是并行执行?

hive会将一个查询转化成一个或多个阶段,这样的阶段可以是mapreduce阶段,limit阶段,或者hive执行过程中可能经历的其他阶段。

默认情况下,hive一次只会执行一个阶段,不过,某个特定的job可能包含众多的阶段,而这些阶段是可以并行执行的,这样可能使整个job执行时间缩短。

通过设置hive.exec.parallel(并行)=true就可以开启并行执行,不过在共享集群中,需要注意,如果Job中并行阶段增多,那么集群利用率就会增加。

set hive.exec.parallel=true;
打开任务并行执行
set hive.exec.parallel.thread.number=16;
同一个sql允许最大并行度,默认为8
当然,得是在系统资源比较空闲的时候才有优势,否则没资源,并行也起不来

五.严格模式

严格模式可以防止用户执行那些可能造成不好影响的查询。开启严格模式:

set hive.mapred.mode=strict;
默认是nonstrict

严格模式限制3种类型的查询

1.对分区表的查询必须在where子句对分区字段限定条件,即不允许扫描所有分区。

2.使用order by 必须学limit

  因为order by为了执行全局排序将所有的结果数据分发到一个reduce task中进行处理。强制要求用户增加这个limit语句可以防止reduce task额外执行很长时间。 

3.限制笛卡尔积

六.推测执行

在分布式集群环境下,因为程序bug(或hadoop本身的bug),资源分布不均等问题,会造成同一个job的多个任务速度不一致的情况。有些任务的运行速度可能明显慢于其他任务(比如一个job的某个任务的进度只有50%,而其他已经执行完毕),则这个任务会拖累job整体的执行进度。为了避免这种情况发生,hadoop采用了推测执行机制,它根据一定的法则推测出“拖后腿”的任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。speculative:推测的

设置开启推测执行参数:Hadoop的mapred-site.xml文件中进行配置
<property>
    <name>mapreduce.map.speculative</name>
    <value>true</value>
</property>

<property>
    <name>mapreduce.reduce.speculative</name>
    <value>true</value>
</property>

hive本身也提供了配置项来控制reduce-site的推测执行
<property>
    <name>hive.mapred.reduce.tasks.speculative.execution</name>
    <value>true</value>
</property>

七.HIve Map优化

1.设置合理的Map个数

通常情况下,job会通过input目录产生一个或多个map task,map task的个数由:

input文件总个数,input文件大小,块的大小决定,有多少片,就有多少个maptask。

1)复杂文件增加Map数

当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数。来使得每个map处理的数据量减少,从而提高任务的执行效率。

增加map的方法:根据下面的公式调节片的大小

computeSlite(Math.max(
minSize,
Math.min(maxSize,blocksize)))=blocksize=128M

调整maxSize最大值,让maxSize最大值低于blocksize就可以增加map的个数.

2)是不是map数越多越好

不是,如果有很多小文件。一个map task处理一个小文件,则每个map task的任务启动和初始化时间远远大于逻辑处理时间,这样会造成大量的资源浪费,而且,同时执行的map task的数量是受限的。

3)是不是每个map处理的接近128M的文件就高枕无忧了?

不一定,比如一个127M的文件,正常会用一个map task去执行,但这个文件中有1个或2个字段,但却有几千万个记录。如果该map处理的逻辑比较复杂,用一个 map任务去做,肯定比较耗时。

3.小文件进行合并(亲测)

1.通过设置读取片的大小来设置
set mapred.max.split.size=1682000000;
切片的最大值
set mapred.min.split.size=1346000000;
切片的最小值
set mapred.min.split.size.per.node=1346000000;
每个节点切片的最小值
set mapred.min.split.size.per.rack=1346000000;
每个机架切片的最小值

2.通过另起一个job来合并小文件
set hive.merge.mapredfiles=true;
对mr进行设置
set hive.merge.mapfiles=true;
only-map进行设置
set hive.merge.smallfiles.avgsize=16000000;默认为16M
set hive.merge.size.per.task=256000000;
合并后每个文件的目标大小,默认为256000000,256M

切分的过程:

1.三个重要的属性:

 mapSplitSize:切片大小的最大值

 minSplitSizeNode:同一个节点的数据块形成切片时,切片大小的最小值

  minSplitSizeRack:通一机架的数据块形成切片时,切片大小的最小值

2.切片形成该过程

  1)不断得带节点列表,逐个节点(以块为单位形成切片)

     遍历累计每个节点上的数据块,如果累加数据块的大小>=maxSplitSize则将这些数据块形成一 个切片.继续改过程,直到剩余数据块累加大小<maxSplitSize,则进行下一步

  2)如果剩余数据块累加大小>=minSizeNode,则将这些数据块形成一个切片。继续该过程,直到数据块累加大小<minSplitSizeNode。然后进行下一步。

  3)不断迭代机架列表,逐个机架(以块为单位),形成切片。如果累加数据块大小>=maxSplitSize,则将这些数据块形成一个切片,直到剩余数据块累加大小<maxSplitSize则进行下一步

  4)遍历并累加所有机架上的剩余数据块,如果累加数据块大小>=maxSplitSize则将这些数据块形成一个切片,继续该过程,直到剩余数据块累加大小<maxSplitSize,则进行下一步。

5)最终将剩余的数据块形成一个切片。

八.设置合理的reduce task数

1.调整reduce个数方法一

1)默认每个Reduce处理的数据量默认是256M
  set hive.exec.reducers.bytes.per.reducer=256000000;
2)每个application最大的reduce数,默认为1009,如果指定为负值,则hive在自动
  确定reducer数量时将此值作为最大的reducer数量. 
  set hive.exec.reducers.max=1009
3)计算reducer数的公式
  N=min(参数2,总输入数据量/参数1)

2.调整reduce个数方法二

在hadoop的maped-default.xml文件中修改
设置每个Job的Reduce个数
set mapreduce.job.reduces=15;默认为-1表示禁用

3.reduce task个数并不是越多越好

过多的启动和初始化reduce task会消耗时间和资源.另外有多少个reduce task就会有多少个输出文件,如果生成了很多小文件,那么如果这些小文件作为下一个任务输入,则会出现小文件过多的问题。

在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数,使单个reduce任务处理数据量大小要合适。

九.数据倾斜

group by数据倾斜:map aggre、skewindata两个job

多个key同时导致数据倾斜:多设置reduce task个数

join数据倾斜:map join、skewjoin两个job、SMB、空值处理

十.explain查看执行计划

用法:
explain extended select xxx from xxx;

十一.谓词下推

将SQL语句的where谓词逻辑都尽可能提前执行,减少下游处理的数据量。对应逻辑优化器是:PredicatePushDown.

set hive.optimize.ppd.=true;谓词下推,默认是true
会自动将join后where中的where提前:先where再join

textfile 和sequencefile的存储格式都是基于行存储的。

十二.合适的文件格式

1.列式存储和行式存储

1)行存储的特点

当查询满足条件的一整行数据时,列存储需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中的第一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。

2)列存储的特点

因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量。表中相同列的值的类型肯定是相同的,列式存储可以针对性的设计更好的压缩算法。

orc和parquet是基于列式存储的。

2.textfile

默认格式,数据不做压缩,磁盘开销大,有序列化和反序列化的开销。压缩后的textfile无法分割和合并,查询效率最低(序列化和反序列化),可以直接存储,load的速度最快。

3.orc格式

建表语句

create table xx(
...
)
row format delimited 
fields terminated by '\t' 
stored as orc tblproperties("orc.compress"="NONE");

snappy压缩:
stored as orc tblproperties("orc.compress"="SNAPPY");

也可以通过alter table来设置
alter table xx set tblproperties('orc.bloom.filter.columns'='*','orc.compress'='SNAPPY');

orc是列式存储的。使用orc格式,可以降低磁盘存储空间,查询效率也不会差,建议使用orc的snappy压缩。

由于数据压缩,数据量变小,所以Job启动后生成的map,reduce数目也会变少,占用的container就会少,所以变相增加了集群的计算能力。

4.parquet

spark默认为parquet,具有很好的压缩性能,可以指定每一列的压缩方式, 可以减少大量的表扫描、序列化和反序列化的时间。支持复杂的嵌套数据烈性:json。

建表语句

create table xxx(
xxx
)
row format delimited
fields terminated by "\t"
stored as parquet
;

--设置压缩格式为snappy,根据需要来设置压缩格式,默认不压缩
alter table xxx tblproperties('parquet.compression'='SNAPPY');

5.总结

1.textfile存储空间消耗比较大,并且压缩的text无法分割和合并。查询效率最低,因为要反序列化。可以直接存储,  load数据的速度最高。

2.orc,查询效率高(二进制存储,不需要反序列化,是自解析的,且为列式存储)。load时需要将text转换成parquet,速度低。因为存储空间少,所以也减少了maptask reducetask,和container的数量,提高集群的计算能力。无论在存储还是查询上,orc都比parquet好。

3.parquet,查询效率高(二进制存储,不需要反序列化,是自解析的,且为列式存储)。load时需要将text转换成parquet,速度低。因为存储空间少,所以也减少了maptask reducetask,和container的数量,提高集群的计算能力。适配spark,impala。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值