HIVE基础
元数据比较
不支持删除和更新语法,也没有必要。因为Hive面向olap,注重数据的分析,而不是oltp面向事务的数据增删改。
hive属于读模式,只有在读取数据的时候才会做数据校验。
hive主要工作面向:创建表,导入数据,写查询分析
支持的SQL语法
表的4种表存储
创建内部表时,则按照图上的方式存储在默认仓库路径
创建外部表时,(此时HDFS已有数据,但是默认仓库路径没有信息)则需要在创建表的时候指定目录
分桶表
分区分桶的使用
分桶用的情况相对较少
Why分桶下可以提高join效率?
比如A和B的id按照奇偶分桶,这样按照id join时A的奇数id只和B奇数id join,偶数也是。
而不需要十字相乘一样全部数据join,只要A和B分桶划分数量成倍数关系即可达到效果。如A 4个,B 2个,4是2的倍数
排序
order by 全局有序,最终一个reduceTask来排序,设置多个也无效,数据量很大则性能很差
sort by 局部有序,每个reduceTask内有序,但全局数据无序
distribute by 分桶查询,1 必须主动设置reduceTask个数 2 必须设置distribute by设置分桶规则:hash散列
cluster by = distribute by + sort by,当 distribute by和sort by的分区字段相同时可以用,但不能设置desc
distribute by + sort by 可以局部排序后再全局排序,提高全局排序的性能。
例如 distrubute by (case when age > 20 一个分区 <=20 一个分区),分区内排序后,再全局 sort by age
内置函数/自定义函数
窗口函数
HIVE HQL调优
调优的四个方向
1 建表设计层面
2 HQL语法和运行参数层面
3 HIVE架构层面
4 HIVE数据倾斜
1 建表设计层面
分区表优化
大量根据某一个字段查询,可以根据该字段来分区
分桶表优化
1 join:a和b表经常按照某个字段join,a表和b表可以根据这个字段分桶
Why分桶下可以提高join效率?
比如A和B的id按照奇偶分桶,这样按照id join时A的奇数id只和B奇数id join,偶数也是。
而不需要十字相乘一样全部数据join,只要A和B分桶划分数量成倍数关系即可达到效果。如A 4个,B 2个,4是2的倍数
2 采样:采样百分比,多少条,多大量的数据
3 选择合适的文件存储格式
4 选择合适的压缩格式
2 HQL语法和运行参数层面
1 查看hive执行计划
2 列裁剪和分区裁剪
只读需要的列和需要的分区
set hive.optimize.cp = true 开启列裁剪,默认开启
3 谓词下推
where谓词逻辑提前执行,减少下游处理量
set hive.optimize.pdd = ture 开关打开后,自动将where任务提前
例如 a join b where b.age > 20 改成 先 select b.age > 20之后再 a join b
4 合并小文件
大量的输入小文件会启动大量mapTask任务,会浪费资源,所以map读取时的小文件可以提前做好合并
set.hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat 将map输入文件合并后按照block大小分割
set.hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat map段不合并
5 合理设置MapTask和ReduceTask并行度
减小MapTask主要通过减少map段文件数量
增大MapTask主要通过控制上一个job的reduceTask数量
6 启用MapJoin
mapjoin和combiner(不影响业务结果条件下),这两个优化是能用则用
mapjoin是通过双方较小的表分发到各个节点内存中,在map阶段直接内存中join,而不是reduce阶段再读磁盘join,从而提高性能
可以通过参数配置后开启的自动执行,或者通过sql语句执行
内存表默认25mb,可以企业中最大调整成2G
Sort-Merge-Bucket(SMB)MapJoin
条件:所有表都是分桶表且分桶排序,表的分桶个数为倍数。是分桶表的归并排序优化,开启SMB开关即可
7 Join数据倾斜优化
8 CBO优化,成本优化器
默认开启,自动优化HQL中多个join顺序,按照执行成本最小的来选择合适的join算法
9 GroupBy 优化
map端预聚合 + groupby reduce端两阶段执行预聚合+最终汇合
10 order by优化
11 count distinct 优化
12 in/exist 语法改写 semi join
13 使用vectorization技术
14 多重模式
可以将多个重复类似的SQL合并为一,一次读取多次插入的sql形式,避免了每次插入都需要读取一次全表
15 启用中间结果压缩
关于如何确定MapTask和ReduceTask问题
mapTask有两种方式
第一种HiveInputFormat
有一个文件100M,mapred.map.tasks = 默认2,dfs.block.size = 默认128M
goalSize = 100 / 2 = 50M
// mapred.min.split.size = 1, minSplitSize = 1
minSize = max {mapred.min.split.size, minSplitSize} = 1
splitSize = max (minSize, min(goalSize, dfs.block.size)) = 50M
计算结果是分片大小是50M,分片数 = 100 / 50 = 2,共两个分片。
一般也就是有多少个输入文件,就是多少个mapTask
第二种CombinHiveInputFormat
block size为128mb,会小文件合并到128mb,超出的再开启第二个分片,依次类推
reduceTask数量计算类似,切片数据总量/per reducer值
HIVE 架构层面优化
1 数据量不大时,启用本地模式执行,不需要集群
2 启用本地抓取
计算逻辑很简单的时候,没必要执行mr任务。直接本地抓取扫描即可
1 如 select * ,where仅仅分区字段过滤,limit普通查询等时候,自动的不会唤起mr任务
2 主动开启本地抓取模式,依然不会唤起mr任务
3 JVM重用
set mapred.job.reuse.jvm.num.tasks = 5 则可由一个jvm执行一个task改成一个jvm串行复用的执行5个task
4 并行执行
5 推测执行
根据一定法则推测出性能低下的task,给这种task多执行一个备份task,最后取运算最快的task结果
6 严格模式
调优场景案例
1 事实表和维度表连接
情况:如日志表连接用户表。连接的小表并不小,mapJoin无法支持。但是又会有数据倾斜
select * from log a left outer join users b on a.user_id = b.user_id
2 连续的大表连接大表
1 log a join log b join c join ...
位图法bitMap,求连续七天发朋友圈的用户
2
大表加随机数id如1-4,小表数据扩容成4倍文件并各自加上id 1-4。
之后大表和小表通过id join,就可以把1个reduceTask变成4个redcueTask,提高并行执行性能
原:select a.age b.sex from a,b
select random(1-4) as id, a.age from a
select 1 as id from b union select 2 as id from b union select 3 as id from b union select 4 as id from b
SQL的MR实现方式
Join 实现
select a.age,b.sex from a join b on a.id = b.id
实现思路:遍历a表id为key,age+1为value,map局部预合并age+数量为value。遍历b表同理,最后通过id为key进行shuffle和reduce合并并解析为需要的结果
GroupBy 实现
Distinct 实现
有多种方式,其中的一种
基本SQL原理
HQL转换MR
四大组件:Driver,Compiler,Optimizer,Executor