基础问题:
hive与传统数据库的区别
1) 表数据验证:传统数据库是写模式,hive是读模式。传统数据库在写入数据的时候就去检查数据格式,hive在读取数据的时候检查。因此,写时模式,查询快,读时模式数据加载快。
2) hive不支持实时处理,并且对索引支持较弱。
3) hive不支持行级插入、更新、删除和事务。
9) 索引。Hive没有,数据库有
10) 执行。Hive是MapReduce,数据库是Executor
11) 可扩展性。Hive高,数据库低
12) 数据规模。Hive大,数据库小
5) 数据存储位置。Hive是建立在Hadoop之上的,所有的Hive的数据都是存储在HDFS中的。而数据库则可以将数据保存在块设备或本地文件系统中。
6) 数据格式。Hive中没有定义专门的数据格式,由用户指定,需要指定三个属性:列分隔符,行分隔符,以及读取文件数据的方法。数据库中,存储引擎定义了自己的数据格式。所有数据都会按照一定的组织存储。
7) 数据更新。Hive的内容是读多写少的,因此,不支持对数据的改写和删除,数据都在加载的时候中确定好的。数据库中的数据通常是需要经常进行修改。
8) 执行延迟。Hive在查询数据的时候,需要扫描整个表(或分区),因此延迟较高,只有在处理大数据是才有优势。数据库在处理小数据是执行延迟较低。
hive的数据类型
Hive的内置数据类型可以分为两大类:(1)、基础数据类型;(2)、复杂数据类型
基本数据类型
数据类型 | 大小 | 范围 | 示例 |
---|---|---|---|
TINYINT | 1byte | -128 ~ 127 | 100Y |
SMALLINT | 2byte | -32768 ~ 32767 | 100S |
INT | 4byte | -2^32~ 2^32-1 | 100 |
BIGINT | 8byte | -2^64~ 2^64-1 | 100L |
FLOAT | 4byte | 单精度浮点数 | 5.21 |
DOUBLE | 8byte | 双精度浮点数 | 5.21 |
DECIMAL | - | 高精度浮点数 | DECIMAL(9,8) |
BOOLEAN | - | 布尔型 | true/false |
BINARY | - | 字节数组 | - |
字符串类型
- Structs:一组由任意数据类型组成的结构。比如,定义一个字段C的类型为STRUCT {a INT; b STRING},则可以使用a和C.b来获取其中的元素值;
- Maps:一组无序的键/值对。键的类型必须是原子的,值可以是任何类型,同一个映射的键的类型必须相同,值得类型也必须相同
- Arrays:一组有序字段。字段的类型必须相同
深入阅读: hive数据类型有哪些?
元数据保存方式
hive是建立在hadoop之上的数据仓库,一般用于对大型数据集的读写和管理,存在hive里的数据实际上就是存在HDFS上,都是以文件的形式存在,不能进行读写操作,所以我们需要元数据或者说叫schem来对hdfs上的数据进行管理。主要有以下三种方式:
1) 内嵌模式:将元数据保存在本地内嵌的derby数据库中,内嵌的derby数据库每次只能访问一个数据文件,也就意味着它不支持多会话连接。
2) 本地模式:将元数据保存在本地独立的数据库中(一般是mysql),这可以支持多会话连接。
3) 远程模式:把元数据保存在远程独立的mysql数据库中,避免每个客户端都去安装mysql数据库。
深入阅读: Hive的架构及元数据三种存储模式
内部表和外部表的区别
- 内部表: 未被external修饰的是内部表,建表时默认创建内部表。内部表数据由Hive自身管理。删除内部表会直接删除元数据(metadata)及存储数据;对内部表的修改会将修改直接同步给元数据。
外部表:被external修饰的为外部表(external table);外部表数据由HDFS管理;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
深入阅读: Hive内部表和外部表的区别详解
分区表和分桶表的区别
- 分区表,Hive 数据表可以根据某些字段进行分区操作,细化数据管理,让部分查询更快,不同分区对应不同的目录;
- 分桶表:分桶表主要用于采样,表和分区也可以进一步被划分为桶,分桶是相对分区进行更细粒度的划分。分桶将整个数据内容按照某列属性值的hash值进行区分,不同的桶对应不同的文件。
深入阅读: Hive的分区表和分桶表的区别
动态分区和静态分区
静态分区与动态分区的主要区别在于静态分区需要手动指定分区数值,而动态分区是通过数据来进行判断。
启用hive动态分区,只需要在hive会话中设置两个参数:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
动态分区是通过位置来对应分区值的。原始表select出来的值和输出partition的值的关系仅仅是通过位置来确定的,和列名并没有关系。
生产环境中一般采用动态分区方式。
简述hive的存储格式
- TextFile
TextFile文件不支持块压缩,默认格式,数据不做压缩,磁盘开销大,数据解析开销大。
- SequenceFile格式
SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以的形式序列化到文件中。这种二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使用value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。 - RCFile
Record Columnar的缩写。是Hadoop中第一个列文件格式。能够很好的压缩和快速的查询性能,但是不支持模式演进。通常写操作比较慢,比非列形式的文件格式需要更多的内存空间和计算量。
RCFile是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。
- ORCFile
存储方式:数据按行分块 每块按照列存储 ,压缩快 快速列存取,效率比rcfile高,是rcfile的改良版本,相比RC能够更好的压缩,能够更快的查询,但还是不支持模式演进。
深入阅读: hive四种存储格式介绍与分析比较
## hive如何将Hql转化为MapReduce
1) 解释器完成词法、语法和语义的分析以及中间代码生成,最终转换成抽象语法树;
2) 编译器将语法树编译为逻辑执行计划;
3) 逻辑层优化器对逻辑执行计划进行优化,由于Hive最终生成的MapReduce任务中,Map阶段和Reduce阶段均由OperatorTree组成,所以大部分逻辑层优化器通过变换OperatorTree,合并操作符,达到减少MapReduce Job和减少shuffle数据量的目的;
4) 物理层优化器进行MapReduce任务的变换,生成最终的物理执行计划;
5) 执行器调用底层的运行框架执行最终的物理执行计划。
HiveSQL -> AST(抽象语法树) -> QB(查询块) -> OperatorTree(操作树)-> 优化后的操作树 -> mapreduce 任务树 -> 优化后的 mapreduce 任务树
过程描述如下:
- SQL Parser:Antlr 定义 SQL 的语法规则,完成 SQL 词法,语法解析,将 SQL 转化为抽象语法树 AST Tree;
- Semantic Analyzer:遍历 AST Tree,抽象出查询的基本组成单元 QueryBlock;
- Logical plan:遍历 QueryBlock,翻译为执行操作树 OperatorTree;
- Logical plan optimizer: 逻辑层优化器进行 OperatorTree 变换,合并不必要的 ReduceSinkOperator,减少 shuffle 数据量;
- Physical plan:遍历 OperatorTree,翻译为 MapReduce 任务;
- Logical plan optimizer:物理层优化器进行 MapReduce 任务的变换,生成最终的执行计划;
hive排序函数的区别
- order by
order by 会对数据进行全局排序,和oracle和mysql等数据库中的order by 效果一样,它只在一个reduce中进行所以数据量特别大的时候效率非常低。
而且当设置 :set hive.mapred.mode=strict的时候不指定limit,执行select会报错,如下:
LIMIT must also be specified。
- sort by
sort by 是单独在各自的reduce中进行排序,所以并不能保证全局有序,一般和distribute by 一起执行,而且distribute by 要写在sort by前面。
如果mapred.reduce.tasks=1和order by效果一样,如果大于1会分成几个文件输出每个文件会按照指定的字段排序,而不保证全局有序。
sort by 不受 hive.mapred.mode 是否为strict ,nostrict 的影响。
- distribute by
DISTRIBUTE BY 控制map 中的输出在 reducer 中是如何进行划分的。使用DISTRIBUTE BY 可以保证相同KEY的记录被划分到一个Reduce 中。
- cluster by
distribute by 和 sort by 合用就相当于cluster by,但是cluster by 不能指定排序为asc或 desc 的规则,只能是升序排列。
UDF相关内容
UDF(User-Defined Functions)即是用户自定义的hive函数。当 Hive 自带的函数并不能完全满足业务的需求,这时可以根据具体需求自定义函数。UDF 函数可以直接应用于 select 语句,对查询结构做格式化处理后,再输出内容。
Hive 自定义函数包括三种:
- UDF: 一对一,也就是通常认知的map功能,一般是在task本地执行,不会发生shuffle。 如:upper、substr函数;
- UDAF:多对一,通常是聚合类函数,那么就会发生shuffle网络传输,如果不做任何优化的话,只在reduce端执行,如果开启了局部优化,那么map端和reduce端都会执行。如sum/min/max;
- UDTF(T:table-generating):一对多,可以和UDF同样认为都是在map端执行的。如 lateral view 与 explode 。
深入阅读: 【Hive】Hive UDF
hive小文件解决方案
定位原因:
(1)动态分区插入数据,产生大量的小文件,从而导致 map 数量剧增;
(2)reduce 数量越多,小文件也越多(reduce 的个数和输出文件是对应的)
(3)数据源本身就包含大量的小文件。
解决方案:
(1)在 Map 执行前合并小文件,减少 Map 数:
//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
(2)设置map输出和reduce输出进行合并的相关参数
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000
(3)开启 JVM 重用
set mapreduce.job.jvm.numtasks=10
row_number(),rank()和dense_rank()的区别
都有对数据进行排序的功能
row_number():根据查询结果的顺序计算排序,多用于分页查询
rank():排序相同时序号重复,总序数不变
dense_rank():排序相同时序号重复时,总序数减少
select name,subject,score
row_number() over(partition by subject order by score desc) rn,
rank() over(partition by subject order by score desc) r,
dense_rank() over(partition by subject order by score desc) dr
from student_score;
name |
subject |
score |
rn |
r |
dr |
Zhang |
English |
84 |
1 |
1 |
1 |
Qian |
English |
84 |
2 |
1 |
1 |
Shun |
English |
78 |
3 |
3 |
2 |
Li |
English |
69 |
4 |
4 |
3 |
… |
Math |
… |
… |
… |
… |
Sort By,Order By,Cluster By,Distrbute By 对比
- order by:会对输入做全局排序,因此只有一个 reducer(多个 reducer 无法保证全局有序)。只有一个 reducer,会导致当输入规模较大时,需要较长的计算时间。
- sort by:不是全局排序,其在数据进入 reducer 前完成排序。
- distribute by:按照指定的字段对数据进行划分输出到不同的 reduce 中。
- cluster by:除了具有 distribute by 的功能外还兼具 sort by 的功能。
故障排查与调优
数据倾斜与优化
什么是数据倾斜?
数据倾斜就是数据的分布不平衡,某些地方特别多,某些地方又特别少,导致在处理数据的时候,有些很快就处理完了,而有些又迟迟未能处理完,导致整体任务最终迟迟无法完成,这种现象就是数据倾斜。
发生数据倾斜的原因
1) key分布不均匀;
2) 数据本身的特性,原本按照日期进行分区,如果在特定日期数据量剧增,就有可能造成倾斜;
3) 建表时考虑不周,分区设置不合理或者过少;
4) 某些 HQL 语句本身就容易产生数据倾斜,如 join。
以下操作可能会导致数据倾斜
1) join
大小表join的时候,其中一个较小表的key集中,这样分发到某一个或者几个的Reduce上的数据就可能远高于平均值;
两张大表join的时候,如果有很多0值和空值,那么这些0值或者空值就会分到一个Reduce上进行处理;
join的时候,不同数据类型进行关联,发生类型转换的时候可能会产生null值,null值也会被分到一个Reduce上进行处理;
2) group by
进行分组的字段的值太少,造成Reduce的数量少,相应的每个Reduce的压力就大;
3) count distinct
count distinct的时候相同的值会分配到同一个Reduce上,如果存在特殊的值太多也会造成数据倾斜。
解决方法
深入阅读: hive数据倾斜原因和解决方法
性能优化
深入阅读: hive优化大全-一篇就够了