1、hive的相关优化
1.1 hive的压缩配置
压缩有什么用?
'好处':
在有限的空间下,存储更多的资源
'坏处':
压缩和解压需要消耗额外的资源
- 通过压缩 优化MR 提升效率
位置一: 'map阶段的输出结果上'
'好处一':当reduce在拉取数据的时候,由于数据已经压缩,所以整个数据量减少,从而减少网络带宽,提升拉取的效率
'好处二':在一些特殊情况下,整个MR只有map 没有reduce的,此时map输出的结果就是最终的结果,对结果进行压缩,减少磁盘存储,提升磁盘利用率
位置二:'reduce阶段到的输出结果上'
reduce的输出就是最终的输出, 会落在HDFS上形成最终的文件,
此文件进行压缩, 减少磁盘存储, 提升磁盘的利用率
- 使用那种数据压缩呢?
选择压缩方案的时候 需要看什么指标呢? 压缩比 和 解压缩的性能
说明:
'压缩比: zlib 和 gz'
'解压缩性能: LZO snappy'
'性价比: snappy'
总结:
当对数据'写入多, 读取少'的情况下, 建议优先考虑压缩比 : zlib (ODS层)
当对数据'读取比较多'的情况下, 建议优先考虑解压缩的性能: snappy (其他层次结构)
如果生产环境中, 公司服务器的磁盘空间比较宽裕的, 建议不管在什么位置上, 都使用snappy压缩方案
-
hadoop提供的压缩方案
注意事项: 对于snappy的压缩方案, 默认的apache版本的hadoop是不支持的, 如果想使用需要对hadoop进行重新编译才可以 而一些商业环境的hadoop版本基本都是直接支持snappy压缩方案: 比如 CDH版本
-
压缩方案的配置
map阶段的压缩配置:
1)开启hive中间传输数据压缩功能
set hive.exec.compress.intermediate=true;
2)开启mapreduce中map输出压缩功能
set mapreduce.map.output.compress=true;
3)设置mapreduce中map输出数据的压缩方式
set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
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;
4)设置mapreduce最终数据输出压缩为块压缩
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
1.2 hive的数据存储格式
hive支持的存储数据的格式主要有:textfile(行式存储),sequencefile(行式存储)、ORC(列式存储)、
parquet(列式存储)
- 什么是行式存储 , 什么是列式存储呢? 以及各有什么优缺点呢?
ORC:
1)将数据先按照进行分隔为多个script片段
2)在每一个片段中按照列式存储数据
3)在每一个script片段中都是有索引信息的
通过实验比对:
ORC格式不管在存储上还是查询上, 都是非常优秀的
- 常用的建表格式: 特别关注
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
-- 关注以下这二行: 存储格式为ORC 同时数据压缩方案为SNAPPY
STORED AS orc tblproperties ("orc.compress"="SNAPPY"); --常用于其他层次表
或者:
STORED AS orc|textFile tblproperties ("orc.compress"="GZ|ZLIB"); --常用于ODS层表
注意事项:
只有textFile支持通过load data 方式来加载数据, 其余数据结构,
都需要通过insert + select方式插入数据
1.3 hive的其他优化
1.3.1 hive的fetch本地抓取
fetch本地抓取:在运行SQL的时候,能不走MR尽量不走MR 直接从HDFS上读取数据即可
- 在那些情况下可以不走MR呢?
在hive中,主要可以通过一个配置,来开启fetch本地抓取:
hive.fetch.task.conversion
可选值:
more (默认值)
minimal
none
more: 当值为more的时候, hive会在以下这几种情况不会走MR
情况一: 查询全部数据 select * from表
情况二: 查询某几个字段的时候 select 字段... from 表
情况三: 执行简单的过滤操作的时候: select 字段... from 表 where 字段='值'
情况四: 执行limit的时候, 也不走MR查找: select * from表 limit 10
minimal: 当值为minimal的时候 ,hive会在以下这几种情况不会走MR
情况一: 查询全部数据 select * from表
情况二: 查询某几个字段的时候 select 字段... from 表
情况三: 执行limit的时候, 也不走MR查找: select * from表 limit 10
none: 当值为none的时候 , hive会将全部的查询SQL走MR
生产环境中, 一般选择为 more ,而more正好默认值, 所以 不需要设置
1.3.2 hive的本地模式
hive的本地模式: 在执行MR的时候, 尽量以本地模式运行方案, 而不是提交到yarn集群
相关hive的配置:
set hive.exec.mode.local.auto=true; 开启hive的本地模式 默认为 false
满足本地运行的条件: 当以下两个条件都满足的时候, 才可以走本地模式
数据大小: set hive.exec.mode.local.auto.inputbytes.max=134217728; 默认为128M
文件数量: set hive.exec.mode.local.auto.tasks.max=4 ; 默认为 4
生产环境配置:
建议直接开启本地默认, 因为hive自动识别是否可以走本地
在实际使用, 这个操作, 只能在测试环境中有效, 在生产数据上配置, 其实意义不大, 因为生产数据远远超过这个值
1.3.3 join 查询优化
默认情况下 翻译后MR 是如何实现join连接的操作呢?
存在问题:
1) 可能出现数据倾斜的问题
2) reduce压力较大
如何解决问题?
- 解决方案: map join
适合于 小表 join 大表的情况
map join相关的参数配置:
set hive.auto.convert.join = true; -- 是否开启map join 默认为true
set hive.mapjoin.smalltable.filesize= 25000000; -- 大小表的阈值
-
中型表和大表的join:
- 方案一:如果可以提前过滤的 建议在join之前过滤掉 以减少join的条数
- 方案二: 如果表中有关键条件的字段上有大量的null 建议将null值替换为随机数
- 方案三: 在分桶表中实施map join(bucket map join)
-
大表和大表join:
- 方案一:如果可以提前过滤的 建议在join之前过滤掉 以减少join的条数
- 方案二:如果表中有关键条件的字段上有大量的null 建议将null值替换为随机数
- 方案三: 在分桶表中实施map join(SMB map join)
-
请注意: 目前 大表和小表进行join的时候, 没有了先后之分了, 无所谓, 但是老版本中, 建议将小表放置在前面, 大表放置后面
1.3.4 group by的优化
group by 的数据倾斜的解决方案:
- 方案一: 通过 combiner(规约) 解决
假设有如下这么一份数据:
s01 张三 大数据一班
s02 李四 大数据一班
s03 王五 大数据二班
s04 赵六 大数据一班
s05 田七 大数据二班
s06 周八 大数据一班
s07 李九 大数据一班
需求: 求每个班级有多少个人?
select 班级名称,count(1) as num from stu group by 班级;
map阶段: 假设map 有二个
map1Task:
k2 v2
大数据一班 {s01,张三,大数据一班}
大数据一班 {s02,李四,大数据一班}
大数据二班 {s03,王五,大数据二班}
大数据一班 {s04,赵六,大数据一班}
map2Task:
k2 v2
大数据二班 {s05,田七,大数据二班}
大数据一班 {s06,周八,大数据一班}
大数据一班 {s07,李九,大数据一班}
reduce阶段: 假设reduce 有二个
reduce1Task: 接收 大数据一班
接收到数据:
k2 v2
大数据一班 {s01,张三,大数据一班}
大数据一班 {s02,李四,大数据一班}
大数据一班 {s04,赵六,大数据一班}
大数据一班 {s06,周八,大数据一班}
大数据一班 {s07,李九,大数据一班}
分组操作:
大数据一班 [{s01,张三,大数据一班},{s02,李四,大数据一班},{s04,赵六,大数据一班},{s06,周八,大数据一班},{s07,李九,大数据一班}]
reduce输出
k3 v3
大数据一班 5
reduce2Task : 接收 大数据二班
接收到数据:
k2 v2
大数据二班 {s03,王五,大数据二班}
大数据二班 {s05,田七,大数据二班}
分组操作:
大数据二班 [{s03,王五,大数据二班},{s05,田七,大数据二班} ]
reduce输出
k3 v3
大数据二班 2
发现 两个reduce之间存在数据倾斜的问题
解决方案一: combiner
假设有如下这么一份数据:
s01 张三 大数据一班
s02 李四 大数据一班
s03 王五 大数据二班
s04 赵六 大数据一班
s05 田七 大数据二班
s06 周八 大数据一班
s07 李九 大数据一班
需求: 求每个班级有多少个人?
select 班级名称,count(1) as num from stu group by 班级;
map阶段: 假设map 有二个
map1Task:
k2 v2
大数据一班 {s01,张三,大数据一班}
大数据一班 {s02,李四,大数据一班}
大数据二班 {s03,王五,大数据二班}
大数据一班 {s04,赵六,大数据一班}
combiner(规约): 提前聚合操作 (将reduce的逻辑提前在每一个map中先做一遍)
输出结果:
k2 v2
大数据一班 3
大数据二班 1
map2Task:
k2 v2
大数据二班 {s05,田七,大数据二班}
大数据一班 {s06,周八,大数据一班}
大数据一班 {s07,李九,大数据一班}
combiner(规约): 提前聚合操作(将reduce的逻辑提前在每一个map中先做一遍)
输出结果:
k2 v2
大数据一班 2
大数据二班 1
reduce阶段: 二个reduce
reduce1Task : 接收大数据一班
接收到数据:
大数据一班 3
大数据一班 2
分组操作:
大数据一班 [3,2]
reduce输出:
k3 v3
大数据一班 5
reduce2Task: 接收大数据二班
大数据二班 1
大数据二班 1
分组操作:
大数据二班 [1,1]
reduce输出:
k3 v3
大数据二班 2
是否解决了倾斜: 解决了
- 解决方案二: 大combiner (官方: 负载均衡)
方案: 利用多个MR实现, 第一个MR 将所有的数据均衡分给不同reduce, 有各个reduce计算出一个局部的结果, 这个过程就是负载均衡过程 (提前聚合操作)
第二个MR: 按照相同key发往同一个reduce, 实现最终聚合操作
案例流程:
假设有如下这么一份数据:
s01 张三 大数据一班
s02 李四 大数据一班
s03 王五 大数据二班
s04 赵六 大数据一班
s05 田七 大数据二班
s06 周八 大数据一班
s07 李九 大数据一班
需求: 求每个班级有多少个人?
select 班级名称,count(1) as num from stu group by 班级;
第一个MR:
map1Task:
k2 v2
大数据一班 {s01,张三,大数据一班}
大数据一班 {s02,李四,大数据一班}
大数据二班 {s03,王五,大数据二班}
大数据一班 {s04,赵六,大数据一班}
map2Task:
k2 v2
大数据二班 {s05,田七,大数据二班}
大数据一班 {s06,周八,大数据一班}
大数据一班 {s07,李九,大数据一班}
特殊点: 让数据进行随机发放, 让每一个reduce都拿到相同个数的数据 (负载均衡)
reduce接收数据:
reduce1Task:
接收到:
大数据一班 {s01,张三,大数据一班}
大数据二班 {s03,王五,大数据二班}
大数据一班 {s06,周八,大数据一班}
大数据一班 {s07,李九,大数据一班}
输出结果:
大数据一班 3
大数据二班 1
reduce2Task:
接收到:
大数据一班 {s02,李四,大数据一班}
大数据一班 {s04,赵六,大数据一班}
大数据二班 {s05,田七,大数据二班}
输出结果:
大数据一班 2
大数据二班 1
第二个MR: 按照相同key发往同一个reduce
map阶段:
大数据一班 3
大数据二班 1
大数据一班 2
大数据二班 1
reduce:
reduce1Task: 大数据一班
接收:
大数据一班 3
大数据一班 2
结果:
大数据一班 5
reduce2Task: 大数据二班
接收:
大数据二班 1
大数据二班 1
结果:
大数据二班 2
总结: 第二种方案, 可以比第一种解决倾斜的问题更加良好
相关的配置:
方案一配置信息:
set hive.map.aggr = true; -- 开启 map端提前聚合(combiner)
set hive.groupby.mapaggr.checkinterval = 100000; -- 每一个map能够聚合最大条目
方案二配置信息:
set hive.groupby.skewindata = true;
1.3.5 MR的并行度设置
指的: 如何调整mapTask的数量 以及reduceTask的数量
- mapTask的数量调整:
mapTask的数量是由什么来决定的呢? 文件的切片决定, 切片的大小默认与blcok大小是一致的
意味着无法直接条件map的数量, '调整map数量需要从文件的切片上'
'比如想mapTask数量变得多一些: 设置切片的大小 小一些 或者输入的文件数量变得多一些'
'比如想mapTask数量变的少一些: 设置切片的大小 大一些 或者输入的文件数量变得少一些'
在hive中, 主要是以调整文件数量为主
- reduceTask的数量调整:
在hive中 reduce的数量默认为 -1 , 由 hive基于数据量来自动调整的
调整方案:
hive.exec.reducers.bytes.per.reducer=256123456; -- 每一个reduce默认处理数据量
hive.exec.reducers.max=1009 ; -- 一个MR中最多可以运行多少个reduce
mapreduce.job.reduces=-1; -- 手动设置reduce的数量, 默认 -1 自动推断
在设置reduce个数的时候也需要考虑这两个原则:
'处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;'
1.3.6 explain 查看执行计划
explain 关键词主要作用 查看当前SQL的执行计划,根据执行计划, 调整一些相关优化措施
语法格式:
explain SQL语句;
1.3.7 并行执行机制
在执行SQL的时候, SQL的执行可能会出现多个阶段, 各个阶段之间有可能出现没有任何的依赖,
此时安排这些阶段并行执行, 从而提升效率
相关配置:
set hive.exec.parallel=true; 是否开启并行执行
set hive.exec.parallel.thread.number=16; 最大允许的并行的数量
提前: 要想并行执行, 必须先的有资源, 如果没有资源, 即使可以并行 那也是无法并发的
1.3.7 严格模式
在hive中, 为了防止一些性能极差的SQL的执行, 专门提供严格模式进行限制
1) 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行
2) 对于使用了order by语句的查询,要求必须使用limit语句
3) 限制笛卡尔积的查询