Hive 优化,
1)优化的宏观角度
架构:这个是最重要的,是全局的
1. 分区表:线上环境是普遍存在的,数据量大,不做好合适的分区会导致查询性能极致下降
2. 合理利用中间结果集
说明:假如sql1子查询包含:select a,b,c,z from xxx group ...
假如sql2子查询包含:select a,b,c,d,e,f from xxx group ....
这时候可以梳理SQL之间的“血缘关系”
创建一张临时表 create table tmp_1 as select a,b,c,d,e,f,z from xxx group ....
这时候,sql1子查询可以:select a,b,c,z from tmp_1 group ...
sql2子查询可以:select a,b,c,d,e,f from tmp_1 group ....
优点:大大减少IO,充分利用好了中间结果集
缺点:依赖性提高了,需要梳理一遍血缘关系
总结:虽然梳理血缘关系可能会耗费大量工作和时间,但是执行效果是显著提升的。(麻烦,但效果好)
语法层面:SQL
执行计划
参数:
set hive.auto.convert.join = true; (0.13.0 默认true)
-- common join 转 map join
set hive.mapred.reduce.tasks.speculative.execution = true; (默认ture)
-- 推测式执行: 同一时间多个相同的task(task是原子性),谁先跑完就采用谁的结果,即:长尾作业
-- 要按实际考虑,假如集群负载已很高,这个参数建议关闭为好
set mapred.job.reuse.jvm.num.tasks = 8;
-- mapreduce中每个task都是进程,启动和销毁都需要大量时间
-- 通过jvm复用后,进程跑完不销毁,第二个task接着用。能节省很多启动销毁时间
-- 如果设置成-1,那么只要是同一个job的task,都可以按顺序在一个JVM上连续执行
set mapred.reduce.tasks = 10
-- reduce数过少,会导致作业执行慢;rudece数过多,会造成小文件多
-- 默认值是-1,但不一定是最好效果
-- 这个参数不是固定的,要根据文件生成情况调整,如果文件过大,就继续放大该配置
set hive.exec.reducers.bytes.per.reducer = 256 000 000
-- 该参数是:每一个reduce处理多少个字节数
-- 0.14.0版本之前大概是1G,0.14.0版本之后,默认是256M。即进来文件是1G,就有4个reduce
2)Column Pruning 列裁剪
1. 说明:假设表有100个字段,常用的只有几个字段,建议在查询时指定字段。
2. 对于行式存储文件(text文本),查几个字段和查100个字段,并没有本质区别
3. 对于列式存储文件(orc/parquet),性能会有大大的改变
3)Partition Pruning 分区裁剪
4)join
big join smal==> mapjoin(工作中不常见)
big join big ==> bucket(分桶)
如:分区下面放桶
t1/pt=20180117/
000000
000001
000002
....
000031
t2/pt=20180117/
000000
000001
000002
....
000031
说明:假如t1的桶000000的ID 和 t2的桶000000的ID 想同,join就是桶与桶之间的join。
注意:桶的数量一般使用2的n次方
5)order by 全局排序
order by 只有1个reduce,(两个的话是做不到排序的),所以生成慎用,1个reduce容易产生数据倾斜
6)sort by 局部排序
每个reduce内部排序
Q:假设sort by 有100个task输出,如果一定要全局排序,该怎么办?
A:??????
7)数据倾斜
1. 产生原因:就是数据分布不均匀(即:key不均匀)。
在做join和groupby和count(distinct xxx)的时候,比如:
1亿 1000w是有userid的,9000w是没有userid
9000w ===> task (绝大部分的作业跑起来很快,但是有个别作业1-2 非常慢,UI:卡在99%)
数据量小:可以跑完,但是慢; 数据量大:根本就跑不玩 oom
2. 解决数据倾斜:-- key打散
set hive.groupby.skewindata = true;
-- 默认为false,这个参数的原理就是以下key打散的原理
set hive.map.aggr = true;
-- 默认为true,在group by 查询的时候,决定是否在map端聚合
-- map端聚合对于mapreduce是combiner的API(本地聚合,小型reduce)
3. key如何打散:
-- udf 写一个UDF,把key进来,再加上一个随机数,返回 key_random
4. 去掉打散key的随机数
-- 也是udf 把key_random的random去掉,返回key