赞
踩
一切优化,仅在瓶颈情况下,资源能够满足运行,绝不调试
hive 优化可以从以下几方面考虑:
hive支持的数据存储格式有TextFile(默认) SequenceFile Parquet ORC,但是尽量使用Parquet和ORC文件存储格式
(1)行式存储:
优点:数据被保存在一起了,insert和update更加容易
缺点:如果查询只涉及某几个列,它会把整行数据都读取出来,不能跳过不必要的列读取
(2)列式存储:
优点:最大的优势是查询时可以快速跳过没有涉及到的列,从而避免全表扫描;支持编码压缩;谓词下推、映射下推
缺点:insert/update会比较麻烦并且不适合扫描小量的数据
相同点:
选择parquet原因:
选择ORC原因:
(1)比Parquet 的压缩效率高(eg:snappy)
(2)ORC存储格式对hive非常友好
(3)支持事务ACID(支持事务的表必须为分桶表)
ACID就是常见数据库事务的四大特性:Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)
(4)支持不同的索引索引机制(意味着orc查询速度快)
ORC为我们提供了两种索引机制:Row Group Index(行组索引) 和 Bloom Filter Index(布隆过滤器)
在stripe(行组)记录了每个字段的最大最小值,当查询中有<,>,=的操作时,会根据最大最小值,跳过扫描不包含的stripes
判读数据在不在,当它说一个值不存在的时候,一定不存在,当它说一个值存在的时候,可能存在
优点:
由于存放的不是完整的数据,所以占用的内存很少,而且新增,查询速度够快
缺点:
无法做到删除数据;只能精准的判断数据不存在问题,而无法精准的判断数据存在问题,并且随着数据的增加,误判率也随之增加
在数据规模很大和工作负载密集的情况下,采用数据压缩对磁盘I/O操作、网络数据传输有极大的帮助
hive 中的压缩就是使用了hadoop中的压缩实现的,所以hadoop中支持的压缩在hive 中都可以直接使用
hadoop中支持的压缩算法:
压缩方式选择时重点考虑:
解压缩速度、压缩率、压缩后是否可以支持切片
压缩格式 | 是否支持切片 | 解压缩速度 | 压缩率 |
---|---|---|---|
snappy | no | 最快 | 很差 |
lzo | yes | 很快 | 很高 |
bzip2 | yes | 最慢 | 最高 |
gzip | no | 一般 | 很高 |
mr压缩方案建议
lzo压缩算法的缺点:
需要手动为文件创建索引,没有索引不支持文件切片
所有压缩算法的缺点:
加重CPU负荷,算法越复杂,解压时间越长
参数设置:
设置map后输出压缩
1.开启hive中间传输数据压缩功能
set hive.exec.compress.intermediate=true;
2.开启mapreduce中map输出压缩功能
set mapreduce.map.output.compress=true;
3.设置mapreduce中map输出数据的压缩方式
set mapreduce.map.outout.compress.codec=
org.apache.hadoop.io.compress.SnappyCodec
org.apache.hadoop.io.compress.GzipCodec
org.apache.hadoop.io.compress.BZip2Codec
org.apache.hadoop.io.compress.Lz4Codec
设置reduce后输出压缩
1.开启hive最终输出数据压缩功能
set hive.exec.compress.output=true;
2.开启mapreduce最终输出数据压缩
set mapreduce.output.fileoutputformat.compress=true;
3.设置mapreduce最终数据输出压缩方式
set mapreduce.output.fileoutputformat.compress.codec =
org.apache.hadoop.io.compress.SnappyCodec
org.apache.hadoop.io.compress.GzipCodec
org.apache.hadoop.io.compress.BZip2Codec
org.apache.hadoop.io.compress.Lz4Codec
4.设置mapreduce最终数据输出压缩为块压缩
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
原因:
有时候数据量不大的表用本地计算模式处理,时间会很短,但是默认情况下会将任务提交到集群,等待资源分配,这个过程不仅繁琐,而且更浪费时间
限制条件:
如果以下任意一个条件不满足,那么即使开启了本地模式,将依旧会提交给YARN集群运行
-- 开启本地模式,默认false
set hive.exec.mode.local.auto = true;
原理:
JVM指代一个Java进程,假设一个mr程序中有100个MapTask,那么Hadoop默认会为每个MapTask启动一个JVM(共100个),JVM频繁的创建和销毁,会导致内存开销较大,为了解决上述问题,Hadoop中提供了JVM重用机制来,JVM重用机制可以使得一个JVM实例在同一个job中被使用N次(不同mr job中不可以),即当一个MapTask运行结束以后,JVM不会进行释放,而是继续供让一个MapTask使用,直到运行了N个以后,就会释放,N的值可以在Hadoop的mapred-site.xml文件中进行配置,通常在10-20之间,也可以再hive中直接进行设置
使用条件:
适用于大量小文件场景,没有大量小文件,就不需要开启。因为开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放
注意事项:
hadoop3.x后已经不再支持该选项
mapred-site.xml
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>15</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
hive
set mapred.job.reuse.jvm.num.tasks=10;
原因:
Hive会将一个查询解析为多个Stage,即阶段(例如MapReduce阶段、抽样阶段、合并阶段、limit阶段),有时候Stage彼此之间有依赖关系,只能挨个执行,但是在一些别的场景下,很多的Stage之间是没有依赖关系的,例如Union语句,Join语句等等,这些Stage没有依赖关系,但是Hive依旧默认挨个执行每个Stage,这样会导致性能非常差,我们可以通过修改参数,开启并行执行,当多个Stage之间没有依赖关系时,允许多个Stage并行执行,提高性能
注意:
线程数设置的越多,程序运行速度越快,但同样更消耗CPU资源
-- 打开任务并行执行,默认为false
set hive.exec.parallel=true;
-- 同一个sql允许最大并行度,默认为8
set hive.exec.parallel.thread.number=16;
当我们执行以下SQL语句:
select id from dept group by id order by id desc;
Hive会使用两个MapReduce来完成这两个操作
,第一个MapReduce做group by,经过shuffle阶段对id做分组,第二个MapReduce对第一个MapReduce的结果做order by,经过shuffle阶段对id进行排序,这样会导致性能相对较差,当我们在Hive中开启关联优化后,可以把分组和排序放在同一个MapReduce中实现
-- 默认false
set hive.optimize.correlation=true;
Hive实现Join时,为了提高性能,提供了多种Join方案,例如适合小表Join大表的Map Join,大表Join大表的Reduce Join,以及大表Join的优化方案Bucket Join等
-- 默认已经开启了Map Join
hive.auto.convert.join=true
-- hive会自动对表数据量进行判读,若到达小表条件,就将小表就加入内存
注意:
Hive会自动判断是否满足Map Join,如果不满足Map Join的条件,则自动执行Reduce Join,但是需要了解Hive是怎么判断哪张表是小表的,以及一些使用限制?
怎么判断是不是小表的?
-- 2.0版本之前的控制属性 (默认25M以下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000
使用限制:
原理:
小表数据首会分发给每个MapTask的内存一份,然后逐次取出大表部分数据和小表进行join,底层不需要经过shuffle
Bucket Join(桶表join又分为2种)
注意:
分桶字段 = Join字段 ,桶的个数相等或者成倍数
-- 开启分桶普通join,默认false
set hive.optimize.bucketmapjoin = true;
-- 开启分桶SMB join
set hive.optimize.bucketmapjoin = true;
-- 默认true
set hive.auto.convert.sortmerge.join=true;
-- 默认false
set hive.optimize.bucketmapjoin.sortedmerge = true;
-- 默认true
set hive.auto.convert.join.noconditionaltask=true;
原理:
经shuffle分组后,将key相同的数据分发到同一个reducer,实现大表之间的join
注意:
Hive会自动判断是否满足Map Join,如果不满足Map Join,则自动执行Reduce Join
insert into table stu1 partition(dt1)
select max(s_birth)
from stu_ori
group by s_age
union all
insert into table stu1 partition(dt2)
select min(s_birth)
from stu_ori
group by s_age;
分析:
上面的SQL语句,就是将每个年龄段的最大和最小的生日获取出来放到同一张表的不同分区中,union all 前后的两个语句都是对同一张表的s_age进行分组,然后分别取最大值和最小值,由于对同一张表的相同字段进行两次分组,这显然造成了极大浪费,使用 from … insert … ,这个语法可避免这种情况
--开启动态分区
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
from stu_ori
insert into table stu1 partition(dt1)
select max(s_birth)
group by s_age
insert into table stu2 partition(dt2)
select min(s_birth)
group by s_age;
我们有如下的用户访问数据 visit.txt
用户id 和 该用户访问的店铺名称
u1 a u2 b u1 b u1 a u3 c u4 b u1 a u2 c u5 b u4 b u6 c u2 c u1 b u2 a u2 a u3 a u5 a u5 a u5 a
建表并导入数据
create table visit
(user_id string,shop string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/modules/input/visit.txt' into table visit;
需求:求每个店铺的UV(访客数)
分析:
需要对顾客进行去重,但要避免使用 distict 关键字,因为这个关键字在使用后所有数据会到一个Reduce Task
,有可能会导致内存溢出,所以可以使用 GROUP BY 再 COUNT 的方式替换
distict
-- 原语句 SELECT shop, count(distinct user_id) uv FROM visit group by shop; -- 优化后语句 SELECT shop, count(*) uv FROM ( SELECT shop, user_id FROM visit GROUP BY shop, user_id ) t1 GROUP BY shop;
原理:
总结:
distinct 耗费内存,但是效率极高,若数据较大时,可能会产生OOM,如果distinct遇到瓶颈,想要调优,第一时间要想到用group by
谓词下推 Predicate Pushdown(PPD)的简单点说就是在不影响最终结果的情况下,尽量将过滤条件提前执行。谓词下推后,过滤条件在map端执行,减少了map端的输出,降低了数据在集群上传输的量,降低了Reduce端的数据负载
谓词下推,这里主要说的是 on 中谓词 where 中谓词,on不仅可以作为连接条件,也可以作为过滤条件
(1)left join:右侧的表过滤条件写在on后面,左侧的表过滤条件写在where后面,性能上有提高
(2)join:写在哪里都一样
(3)full join:过滤条件写在 where 后可以谓词下推,写在 on 后不可以谓词下推(默认cbo引擎下)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。