Hive常见优化总结

目录

一、数据倾斜

分桶优化使用场景:优化大表和大表的join

原理:

二、运行时优化

三、编译时优化

四、union的优化

五、group by优化

六、presto内存优化


一、数据倾斜

1. 本地模式

  • 设置参数

    • set hive.exec.mode.local.auto=true;
  • 同时满足3个条件

    • 输入的数据量大小小于128M

    • Maptask的个数小于等于3

    • reducetask的个数小于等于1

2.fetch抓取

  • 设置参数

    • set hive.fetch.task.conversion=more;   ###默认是more  
    • 设置为more之后,select*from table;select *from table limit 1;不会执行MapReduce过程

3.空key的处理

  • 当事实表是日志类数据时,往往会有一些项没有记录到,我们试情况会将它置为null,或者空字符串,-1等。如果缺失项很多,在做join时这些空值就会非常集中,拖累进度。因此,若不需要空值数据,就提前写where语句过滤掉。需要保留的话,将空值key用随机方式打散。

4.join优化

4.1 map端的join优化

如果有reduce阶段,相同key的值发送到同一个reduce,某些 reduce可能因为处理的数据量过大,导致数据倾斜

为了避免数据倾斜,可以采用避免产生reduce阶段来解决,使用map端join策略

map 端join的相关参数

#开启map端join参数
set hive.auto.convert.join=true;
#小表的参数,默认25M
set hive.mapjoin.smalltable.filesize=25000000;

4.2bucket-mapjoin操作

如果两个表进行连接操作,一张表的数据比较小但是远远超过小表参数,而且这个SQL数据倾斜。一样采用在map端join操作,避免reduce阶段,从而解决数据倾斜的问题

使用桶表替代原来的表

1.创建两个桶表,发桶字段是连接字段
2.2个表的分桶个数呈倍数关系
3.将原来的表数据写入桶表里面,在SQL脚本用桶表替换原来的表

开启相关参数

---开启桶表的map端join优化
set hive.optimize.bucketmapjoin=true

4.3 SMB JOIN 优化方法

针对两个表的数据量都很大,非常容易产生数据倾斜。采用类似与map端join的方法,让两个大表连接到时候在map端进行连接,避免reduce阶段产生

优化方法

参数

---写入数据强制分桶
set hive.enforce.bucketing=true;
---写入数据强制排序
set hive.enforce.sorting=true;
---开启bucketmapjoin
set hive.optimize.bucketmapjoin=true;
---开启SMB JOIN
set hive.auto.convert.sortmerge.join=true;
set hive.auto.convert.sortmerge.join.nocoditionaltask=true;

桶表的设置

1.创建2个桶表,分桶字段是连接字段
2.根据粪桶字段进行排序,而且2个表的排序是一样的
3.分桶个数保持一致

将原表数据写入分桶表,用桶表替换原来的表进行sort merge bucket join优化


分桶优化使用场景:优化大表和大表的join

原理:

  1. 如果大表和大表使用mapreduce的普通模式,会在reduce端shuffle,一是慢,二是容易出现异常

  2. 而分桶表将大表的数据划分为一个个小块,分别在Map端做join。之所以可以这样,是因为分桶表在建表的社会,需要指定分桶的字段,对这个字段值取hash后对桶的个数取余数获得一个值,根据这个值将数据放到不同的桶里去。相同key的数据都在一个桶里,在表和表关联的时候就不需要去扫描整个表,只需要扫描对应桶里的数据即可

  3. 由于不同的数据落到哪个桶是由分桶个数决定的,所以做join的两个分桶的同个数必须是相等或者成倍数

  4. 分桶表的每个桶必须要排序,这样可以更高效的做map join


5.code2

5.1 maptask code2问题

maptask调参

1.有次调度工具发送了告警邮件,开发的某个任务报错了
2.查看对应的脚本以及报错信息,发送报错的是map端的code2,当时查看信息发现mapper执行任务99%,任务进度就一直卡在99%
3.确认是map端的code2问题,原因是maptask处理的数据量过大导致的数据倾斜
4.调整单个maptask处理的数据量大小,默认为256m。将其调成300m,350m,400m,对应执行时间,发现300m跑的最快
set hive.exec.mappers.bytes.per.mapper=256000000;
set hive.exec.mappers.bytes.per.mapper=300000000;
5.将的单个mapper处理的数据量大小定位300m

5.2 reducetask code2问题

1.某天调度工具发送告警日志,有个任务报错
2.查看任务对应的脚本和日志,发现是reduce端报数据倾斜code2.因为发现redduces执行任务进度到95%就不动了
error:MapRed reducetask code2
3.因为数据倾斜导致某个reducetask跑了很久没有执行成功,最后报错
4.调整单个reducer处理的数据量大小,默认为256M,将此参数改成300,350,400分别执行了一遍,发现在300m的时候执行的时间最短,因此将参数改为300m执行
set hive.exec.reducers.bytes.per.reducer=256000000;
set hive.exec.reducers.bytes.per.reducer=300000000;
5.任务重启,执行成功

二、运行时优化

  • 开启参数

    • set hive.optimize.skewjoin=true;
  • 运行时的优化思想

    • 当某个key的数据太大可能会导致数据倾斜,就将这些数据划分多个maptask来处理

三、编译时优化

  • 开启参数

    • set hive.optimize.skewjoin.compiletime=true;
  • 思想

    • 已经只知道写入表数据的哪些字段的值会产生数据倾斜的可能,那么就在建表的时候指定会倾斜的字段,以及对应的值

    • CREATE TABLE list_bucket_single (key STRING,value STRING)
      --  倾斜的字段和需要拆分的key值
      SKEWED BY (cid) ON (01)
      --  为倾斜值创建子目录单独存放
      [STORED AS DIRECTORIES];
      • SKEWED BY (cid) :cid有可能会数据倾斜
        ON (01):01代表这个值数据量比较大,可能倾斜

四、union的优化

  • 当开启运行时的优化和编译时的优化之后,在所有的数据计算完,会将所有结果通过union all合并在一起,这样会产生一个MapReduce阶段,会增加任务的执行时间

  • 如果想减少任务的执行时间,可以开启移除union阶段

    • 好处

      • 减少了任务的执行时间

    • 坏处

      • 会产生很多小文件

  • 建议开启

    • ---join运行时的优化
      set hive.optimize.skewjoin=true;
      ---join编译时的优化
      set hive.optimize.union.remove=true;
      ---当有运行时的优化或者编译时的优化,建议开启移除union操作
      set hive.optimize.union.remove=true;
      ​

五、group by优化

5.1 2次mapreduce

  • 开启参数

    • set hive.groupby.skewindata=true;
  • 思想

    • 1.第一次MapReduce的时候,reduce是随机拉去数据到本地,进行计算
      2.第二次MapReduce的时候,相同key的值发送到同一个reduce进行计算,得到最终的结果

5.2 map端的预聚合

  • map端的预聚合

    • set hive.map.aggr=true;
  • 思想

    • 在map端处理完数据之后,在map端进行combiner,减少数据量
      后续reduce阶段拉取的数据变少了,从而有效解决数据倾斜的问题
  • 总结

    • group by的优化,都是从map阶段入手的,减少map阶段数据的输出,reduce阶段处理的数据量变少,从而有效避免数据倾斜

六、presto内存优化

1.presto常规优化手段

  • 采用orc存储格式

    • Presto对ORC文件读取做了特定优化,因此在hive中创建Presto使用的表时,建议采用ORC格式存储。相对于Parquet,Presto对ORC支持更好

  • 建议对数据进行压缩,因为snappy的解压速度更好,建议使用snappy

    • 数据压缩可以减少节点间数据传输对IO带宽压力,对于即席查询需要快速解压,建议采用Snappy压缩

  • 对数据进行预排序

  • 合理设置分区个数

    • 与hive类似,presto会根据元数据信息读取分区数据,合理的分区能减少presto数据读取量,提升查询性能

2.presto在sql上面的优化

  • 不要写*查询数据

    • 由于采用列式存储,选择需要的字段可以加快对字段的读取,减少数据量。避免采用*读取所有字段

  • 根据分区查询数据

    • 对于有分区的表,where语句中优先使用分区字段进行过滤

  • group by先对分组多的字段进行分组,然后再对分组少的进行group by

    • 合理安排Group by语句中字段顺序对性能有一定提升,将group by语句中字段按照每个字段distinct数据多少进行降序排列

  • order by +limit

    • order by需要扫描数据到单个worker节点进行排序,导致单个worker需要大量内存。如果是查询Top N或者Bottom N,使用limit可减少排序计算和内存压力

  • regexp_like替代like

  • 大表放左边

    • Presto中join的默认算法是mapjoin,即将join左边的表分割到多个worker,然后将join右边的表数据整个复制一份发送到每个worker进行计算。如果右边的表的数据量太大,则会报oom

      • 当两个大表进行join是,使用hash join,先将大表按照hash算法分成多个小表,然后进行对应join,其实也是mapreduce思想

    • 因为在presto里面会自动将左边的大表切割之后分发给每个worker,然后将右边的小表复制到每个worker里面进行处理

  • rank替代row_number

3.内存调优

  • 当内存不够的时候可以适当调大用户内存,将第三方内存适当调小

  • 面试题:presto的调优

    • 内存调优

      • 因为presto是一个内存式计算的引擎,非常消耗内存

      • presto的内存分为:预留内存和general内存。而预留内存长时间不用就资源浪费了,可以适当调小预留内存或者直接引用预留内存,调大用户内存

      • 适当调小第三方内存,将内存加到用户内存里面,有效避免内存溢出oom

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值