Hive个人心得笔记之Hive优化

                            Hive个人心得笔记之Hive优化

一.Hive的优化

Hive的优化

  1. 小表缓存:将小表的放入内存中,减少对磁盘以及网络消耗
  2. 在做join查询的时候,如果有附带的查询条件,那么最好先用子查询将符合条件的数据查询出来之后再进行连接查询 - 目的:减少笛卡尔积的数据量
  3. 如果去重和聚合同时出现,尽量先用子查询进行去重,然后再进行聚合

1.map side join

  • mapJoin的主要意思就是,当连接的两个表是一个比较小的表和一个特别大的表的时候,可以把比较小的table直接放到内存中去,然后再对比较大的表格进行map操作,此时join就发生在map操作的时候,每当扫描一个大的table中的数据,就要去去查看小表的数据,哪条与之相符,继而进行连接。这里的join并不会涉及reduce操作。map端join的优势就是在于没有shuffle,在实际的应用中,设置方式:set hive.auto.convert.join=true;
  • hive有一个参数:hive.mapjoin.smalltable.filesize,默认值是25mb(其中一个表大小小于25mb时,自动启用mapjoin)
  • 要求:在hive做join时,要求小表在前(左)

2.join语句优化

  • 优化前:select m.cid,u.id form order m join customer u on m.cid=u.id where m.dt=’20160801’;
  • 优化后:select m.cid,u.id from (select cid from order where dt=’20160801’)m join customer u on m.cid = u.id
  1. // 假设:order - 1000 customer - 1000
  2. // 假设:cid = id = 300
  3. // dt = 20160801 --- 100
  4. 优化前:select m.cid,u.id from order m join customer u on m.cid=u.id where m.dt='20160801'; 
  5. 在底层先做笛卡尔积(1000*1000=100W),然后从笛卡尔积(100W)中找m.cid=u.id(300),再从符合条件的数据中找m.dt(100)
  6. 100W - 300 - 100
  7. 优化后:select m.cid,u.id from (select cid from order where dt='20160801')m join customer u on m.cid = u.id;
  8. 从order中找m.dt(1000 - 100),然后将找之后的数据和customer做笛卡尔积(1000*100=10W),最后从笛卡尔积中找m.uid=c.id(300)
  9. 1000 - 10W - 300

3.group by 优化

  • 调优参数:set hive.groupby.skewindata=true;
  • 数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作
  • 由上面可以看出起到至关重要的作用的其实是第二个参数的设置,它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上,所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜

select count(w) from words group by w;
假设这种方式是对单词的个数进行统计
group by - 实际上对应了MapReduce中的Partition操作 - group by出来有多少个group就意味着有多少个分区,每一个分区要对应一个ReduceTask
hello hadoop
hello hive
hello flume source
hello hadoop yarn

hello - ReduceTask
hadoop - ReduceTask
flume - ReduceTask
100G --- 60G 3G flume 5G Hadoop ...
在给定这些数据中,hello的数量偏多,flume的数据量偏少,那就意味着处理hello的ReduceTask要计算的总量要偏多 --- 数据倾斜
分而治之

4.count distinct 优化

  • 优化前:select count(distinct id )from tablename
  • 优化后:select count(*) from (select distinct id from tablename)tmp;

1.分析:

  1. 优化前
    1. 由于对id=引入了distinct操作,所以在Map阶段无法利用combine对输出结果去消重,必须将id作为key输出
    2. 在reduce阶段再对来自于不同的MapTask的结果进行消重,计入最终统计值
    3. 由于ReduceTask的数量默认为1,所以导致MapTask的所有结果都只能由这一个ReduceTask处理,这就使得ReduceTask的执行效率成为整个任务的瓶颈
    4. 虽然在使用hive的时候可以通过set mapred.reduce.tasks设置ReduceTask的数量,但是Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指定的Reduce Task数,而强制使用1

Hive个人心得笔记之Hive优化_第1张图片

 

  1. 优化后:
    1. 利用Hive对嵌套语句的支持,将原来一个MapReduce作业转换为两个作业:在第一阶段选出全部的非重复id,在第二阶段再对这些已消重的id进行计数
    2. 在第一阶段我们可以通过增大Reduce的并发数,并发处理Map输出
    3. 在第二阶段,由于id已经消重,因此COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。这样即使第二阶段Hive强制指定一个Reduce Task,极少量的Map输出数据也不会使单一的Reduce Task成为瓶颈
    4. 这一优化使得在同样的运行环境下,优化后的语句执行只需要原语句20%左右的时间

 

Hive个人心得笔记之Hive优化_第2张图片

优化前:select count(distinct id )from a;
去重:distinct - 无论有多少个map,在map阶段无法进行合并(combine) - 需要全部的值都发往Reduce,然后在Reduce才真正进行去重 - 如果不指定默认只有一个ReduceTask - set mapreduce.reduce.tasks = 5
聚合:因为聚合函数的参与,为了保证最后的结果会全部聚合在一块,强制只存在一个ReduceTask

优化后:select count(*) from (select distinct id from a)tmp; 
虽然无法在map端去重,但是可以设置多个ReduceTask
 

5.调整切片数(map任务数)

  1. Hive底层自动对小文件做了优化,用了CombineTextInputFormat,将做个小文件切片合成一个切片。如果合成完之后的切片大小>mapred.max.split.size 的大小,就会生成一个新的切片
  2. mapred.max.split.size 默认是128MB,设置方式为:set mapred.max.split.size=134217728(128MB)
  3. 对于切片数(MapTask)数量的调整,要根据实际业务来定,比如一个100MB的文件包含了有1千万条数据,此时可以调成10个MapTask,则每个MapTask处理1百万条数据。

6.JVM重利用

  1. 设置方式:set mapred.job.reuse.jvm.num.tasks=20(默认是1个)
  2. JVM重用是hadoop调优参数的内容,对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况
  3. JVM重用可以使得一个JVM进程在同一个JOB中重新使用N次后才会销毁。

7.启用严格模式

  1. 用户可以通过 set hive.mapred.mode=strict 来设置严格模式,改成unstrict则为非严格模式
  2. 在严格模式下,用户在运行如下query的时候会报错:
    1. 分区表的查询没有使用分区字段来限制
    2. 使用了order by 但没有使用limit语句(如果不使用limit,会对查询结果进行全局排序,消耗时间长)
    3. 产生了笛卡尔积

8.关闭推测执行机制

  • 通常在测试环境下机会确定应用程序是否跑通,如果还加上推测执行,那么在数据分片本来就会发生数据倾斜,执行执行时间就是比其他的时间长,那么hive就会把这个执行时间长的job当作运行失败,继而又产生一个相同的job去运行,造成资源的浪费。可通过如下设置关闭推测执行:
  • set mapreduce.map.speculative=false
  • set mapreduce.reduce.speculative=false
  • set hive.mapred.reduce.tasks.speculative.execution=false

你可能感兴趣的:(HIVE)