文章目录
Hive将SQL转为MapReduce的流程
- Antlr定义SQL的语法规则, 完成SQL词法、语法解析,将SQL转换为抽象语法树AST Tree
- 遍历AST Tree,抽象出基本组成单元QueryBlock(查询块)
- 遍历QueryBlock,翻译为执行操作树OperatorTree
- 逻辑层优化器进行OperatorTree优化,合并不必要的ReduceSinkOperator,减少shuffle数据量
- 遍历OperatorTree,翻译为MapReduce任务
- 物理层优化器进行MapReduce任务的优化,生成最终的执行计算。
数据倾斜
表现
数据倾斜表现在map/reduce执行时,reduce节点大部分执行完成,只有一个或几个reduce节点运行很慢,导致整个程序的处理时间很长。
原因
数据倾斜可能发生在group和join阶段
- key分布不均匀,某个/些key的数据比其他key多很多,导致这个key所在节点的数据量很大。
- 业务数据本身的特性
- 建表考虑不周全
- HQL语句本身存在数据倾斜
解决方式
大表和小表关联时
-
将数据分布均匀的小表放在前面,可以触发reduce端更少的操作次数
-
使用map join将小表缓存到内存中,在map端完成join的过程。
开启map-side-join的属性:set hive.auto.convert.join=true
设置优化小表的大小:set hive.mapjoin.smalltable.filesize=25000000
大表和大表关联时
-
空值或0比较多时,可以对异常值赋一个随机值来分散key,均匀分配给多个reduce执行
-
通过配置参数,让hive自己进行优化。
set hive.exec.reducers.bytes.per.reducer=1000000000,也就是每个节点的reduce默认是处理1G的数据。
set hive.optimize.skewjoin=true 开启join数据倾斜的优化。
set hive.skewjoin.key=skew_key_threshold 控制数据倾斜的阈值
-
对于特殊明确的几个key导致的倾斜,可以单独提取出来进行关联,将结果进行union all合并
group数据倾斜时
-
通过配置参数,让hive自己进行优化。
set hive.map.aggr=true,代表在map端进行聚合,相当于combiner
set hive.groupby.skewindata=true,表示有数据倾斜时进行负载均衡,生成的查询计划会有两个MR job。第一个MR job中,map的输出结果随机分布到reduce中,每个reduce做部分聚合操作,并输出结果。这样做的结果是相同的group key可能分发到不同的reduce中,从而达到负载均衡的作用。第二个MR Job在根据预处理的数据结果按照group by key分布到reduce中,最后完成最终的聚合操作。
set hive.groupby.mapaggr.checkinterval = 100000 (默认)执行聚合的条数
通用方式
-
增大reduce的数量
set mapred.reduce.tasks=100,指定reduce的个数
如果不指定reduce的数量,默认是通过hive.exec.reducers.bytes.per.reducer来计算reduce 的数量。
Hive的优化?
本地模式
当hive输入数据量很小时,触发job执行时间比数据处理时间还长
set hive.exec.mode.local.auto=true 启动本地模式优化
并行执行
并行执行job的多个阶段,提高集群的利用率
set hive.exec.parallel=true
严格模式
通过set hive.mapred.mode=strict开启严格模式,有以下3个约束:
- 对于分区表,where中必须有分区字段过滤条件
- 对于order by查询,必须有limit
- 限制笛卡尔积
小文件处理
控制小文件的生成:减少reduce的数量
对已存在小文件的处理方案:
- 使用Hadoop Achieve对小文件进行归档
- 重建表,建表时减少reduce的数量
- 调节mapper/reducer数量
调整mapper和reducer的数量
hive会将查询分为一个或多个MapReduce任务达到并行的目的。
适当的调整mapper和reducer数量,可以加快运行的速度
调整mapper数量
https://www.cnblogs.com/chengdu-jackwu/p/10170895.html
mapper数量的决定因素有:input的文件总个数、input的文件大小、集群设置的文件块大小
可以通过以下参数调整:
set mapred.max.split.size=100000000; – 决定每个map处理的最大的文件大小,单位为B
set mapred.min.split.size.per.node=100000000; – 节点中可以处理的最小的文件大小
set mapred.min.split.size.per.rack=100000000; – 机架中可以处理的最小的文件大小
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;—实现map中的数据合并
调整reducer数量
reducer数量是按照输入的数据量来确定的。
参数hive.exec.reducers.bytes.per.reducer的默认值是1GB,表示每个reduce处理1GB的数据。
hive默认的reducer数量是3,可以通过设置mapred.reduce.tasks的值来修改。
为了控制资源的利用情况,华兴hive.exec.reducers.max也必须设置,限制最大reducer数量
JVM重用
对于task数量多的job,可以开启JVM重用,使得JVM实例在同一个job中重复使用N次。
N的值通过mapred.job.reuse.jvm.num.tasks设置
推测执行
触发执行一些重复的任务。解决部分task由于机器资源紧张而久久不能完成的问题。
set hive.mapred.reduce.tasks.speculative.execution=true开启推测执行
几种排序的区别:
order by 对输入做全局排序,因此只有一个reduce,输入规模过大时,需要比较长的计算时间
sort by 不是全局排序,在数据进入reduce前完成排序,保证每个reduce输出有序,不保证全局有序
distributed by 根据制定的内容将数据分到同一个reduce中
cluster by 除了具有 distribute的功能外,还会对该字段进行排序(分桶)
Hive的特点
- 将结构化数据文件映射为数据库表,提供完整的sql查询能力
- 本质是在MapReduce上加了一层sql的壳,是一种离线数据分析工具
- 通过制造冗余来提高查询能力
- 不支持强事务
Hive的一些概念
数据库:底层是HDFS中国一个库名.db的文件夹
表:库名文件夹下以表名为名字的子文件
行数据:表名文件夹下的文件
HQL:会转换成底层的mapreduce执行
default库:对应hdfs中的/user/hive/warehouse
内部表外部表
未被external修饰的表是内部表(managed table),被external修饰的是外部表(external table)
内部表的数据是由Hive自身管理的,外部表的数据是由HDFS管理的。
删除内部表会删除元数据和存储的数据;删除外部表只删除元数据不删除存储的数据。内部表的数据在hive中删除,在HDFS中也就删除了;但是外部表的数据,在Hive中删除,HDFS中还是存在的。
insert into和insert overwrite
insert into 与 insert overwrite 都可以向hive表中插入数据,但是insert into直接追加到表中数据的尾部,而insert overwrite会重写数据,先进行删除,再写入。
如果存在分区的情况,insert overwrite会只重写当前分区数据。
Hive元数据库中的表
DBS存储了库相关信息,库编号、库名称、库所有者、库对应在HDFS中的位置
TBLS存储了表相关信息,表的编号、所属库编号、表所有者、表名称、表类型等
COLUMN_V2存储了对应列的信息,列编号、列名称、列类型、列位置等
SDS存储了表在HDFS中存储的吻戏信息,表的编号和存储位置
分区和分桶的区别
分区
是指按照数据表的某列或某些列分为多个区,区从形式上可以理解为文件夹,比如我们要收集某个大型网站的日志数据,一个网站每天的日志数据存在同一张表上,由于每天会生成大量的日志,导致数据表的内容巨大,在查询时进行全表扫描耗费的资源非常多。
这个情况下,我们可以按照日期对数据表进行分区,不同日期的数据存放在不同的分区,在查询时只要指定分区字段的值就可以直接从该分区查找。
分桶
分桶是相对分区进行更细粒度的划分。
分桶将整个数据内容安装某列属性值得hash值进行区分,如要按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。
如取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件。
left join和left semi join区别
left join就是left outer join,返回左右表符合on条件的数据。如果右表和左表有多条数据匹配,就会返回多条数据。
left semi join左半连接,返回符合on条件的左表的数据。如果右表和左表有多条数据匹配,只会返回一次左表的数据。