在介绍hive存储格式之前,我们先来了解一下行式存储与列式存储的区别。
1、行式存储
优点:
一条数据就是一行,比较符合面向对象的思维,所有信息都放在一起。这种存储格式可以很方便的进行insert/update操作。
缺点:
a、如果只需要查询几个列的数据,它会读取所有的列的数据,而不能跳过不需要的列。一般在数据量比较大的时候性能影响比较明显。
b、由于每一行中有很多不同的数据类型,无法获得一个很高的压缩比,也就是说无法节省更多的磁盘空间。
c、不是所有的列都适合索引。
2、列式存储
优点:
a、查询的时候只需要查自己所需要的列,可以跳过不需要的列。
b、可以有极高的压缩比,不仅节省存储空间,也节省计算内存和CPU。
c、任何列都可以作为索引。
缺点:
a、insert/update操作不方便
b、不适合少量的数据
根据hive官网文档,我们在创建hive表的时候,下面有一个可选的参数
[STORED AS file_format]
它的含义就是指定hive表底层数据的存储格式file_format。它和之前介绍的压缩compression是不同的概念。链接是压缩的介绍。(https://blog.csdn.net/qq_34382453/article/details/84942177)
根据文档显示,file_format有下面的几类:
file_format:
: SEQUENCEFILE
| TEXTFILE -- (Default, depending on hive.default.fileformat configuration)
| RCFILE -- (Note: Available in Hive 0.6.0 and later)
| ORC -- (Note: Available in Hive 0.11.0 and later)
| PARQUET -- (Note: Available in Hive 0.13.0 and later)
| AVRO -- (Note: Available in Hive 0.14.0 and later)
| JSONFILE -- (Note: Available in Hive 4.0.0 and later)
| INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
下面我将一一介绍这几种file_format。首先说一下,在hive交互端上,我们要查询某一个参数的值,是用set命令。如上面的介绍
| TEXTFILE -- (Default, depending on hive.default.fileformat configuration)
我们要查看参数hive.default.fileformat ,即默认的存储格式的值,应该在hive交互端使用如下命令,就可以查看。
set hive.default.fileformat
当然,如果我们需要设置参数,也是用set命令,例如我们想设置默认的存储格式为RCFILE,那么我们可以用如下命令:
set hive.default.fileformat = RCFILE
1、SEQUENCEFILE
1.1 sequenceFile文件是Hadoop用来存储二进制形式的[Key,Value]对而设计的一种平面文件(Flat File)。
1.2 可以把SequenceFile当做是一个容器,把所有的文件打包到SequenceFile类中可以高效的对小文件进行存储和处理。
1.3 SequenceFile文件并不按照其存储的Key进行排序存储。
1.4 在存储结构上,SequenceFile主要由一个Header后跟多条Record组成,Header主要包含了Key classname,value classname,存储压缩算法,用户自定义元数据等信息。此外,还包含了一些同步标识,用于快速定位到记录的边界。每条Record以键值对的方式进行存储,用来表示它的字符数组可以一次解析成:记录的长度、Key的长度、Key值和value值,并且Value值的结构取决于该记录是否被压缩。
1.5 有以下三种类型的压缩
A、无压缩类型:如果没有启用压缩(默认设置)那么每个记录就由它的记录长度(字节数)、键的长度,键和值组成。长度字段为4字节。
B、记录压缩类型:记录压缩格式与无压缩格式基本相同,不同的是值字节是用定义在头部的编码器来压缩。注意:键是不压缩的。
C、块压缩类型:块压缩一次压缩多个记录,因此它比记录压缩更紧凑,而且一般优先选择。当记录的字节数达到最小大小,才会添加到块。该最小值由io.seqfile.compress.blocksize中的属性定义。默认值是1000000字节。格式为记录数、键长度、键、值长度、值。
1.6、如果你想把普通的文件数据加载到SequenceFile类型的表中,需要进行一步中间转化操作。即先把数据load到存储格式为textfile的表中,再用insert + select语句插入到SequenceFile存储格式的表中。
2、TEXTFILE
即普通的文本格式,行式存储。hive默认的存储格式就是textfile。在实际工作中很少用。
3、RCFILE
rcfile是由Facebook提出的一种行列混合的存储格式。它是基于SEQUENCEFILE实现的列存储格式。它即满足快速数据加载和动态负载高适应的需求外,也解决了SEQUENCEFILE的一些瓶颈。该存储结构遵循的是“先水平划分,再垂直划分”的设计理念。先将数据按行水平划分为行组,这样一行的数据就可以保证存储在同一个集群节点;然后在对行进行垂直划分。
我们来看一下HDFS块内RCFile方式存储的示例图:
RCFile是在Hadoop HDFS之上的存储结构,该结构强调:
1、RCFile存储的表是水平划分的,分为多个行组,每个行组再被垂直划分,以便每列单独存储;
2、RCFile在每个行组中利用一个列维度的数据压缩,并提供一种Lazy解压(decompression)技术来在查询执行时避免不必要的列解压;
3、RCFile支持弹性的行组大小,行组大小需要权衡数据压缩性能和查询性能两方面。
每个HDFS block块中,RCFile以行组为基本单位来组织记录。也就是说,存储在一个HDFS块中的所有记录被划分为多个行组;对于一张表所有行组大小都相同,一个HDFS块会有一个或多个行组。
一个行组包括三个部分:
1、第一部分是行组头部的同步标识,主要用于分隔HDFS块中的两个连续行组;
2、第二部分是行组的元数据头部,用于存储行组单元的信息,包括行组中的记录数、每个列的字节数、列中每个域的字节数;
3、第三部分是表格数据段,即实际的列存储数据。在该部分中,同一列的所有域顺序存储。从上图可以看出,首先存储了列A的所有域,然后存储列B的所有域等。
RCFile的每个行组中,元数据头部和表格数据段(每个列被独立压缩)分别进行压缩,RCFile使用重量级的Gzip压缩算法,是为了获得较好的压缩比。另外在由于Lazy压缩策略,当处理一个行组时,RCFile只需要解压使用到的列,因此相对较高的Gzip解压开销可以减少。
RCFile具备相当于行存储的数据加载速度和负载适应能力,在读数据时可以在扫描表格时避免不必要的列读取,它比其他结构拥有更好的性能,使用列维度的压缩能够有效提升存储空间利用率。
4、ORC
下面这篇博客写得很详细,如有需要可参考。ORC也是一种列式存储格式。是现在主流的存储格式。
https://blog.csdn.net/cnhome/article/details/80241197
5、PARQUET
PARQUET是是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Mapreduce、Spark等),被多种查询引擎支持(Hive、Impala、Drill等),并且它是语言和平台无关的。Parquet最初是由Twitter和Cloudera合作开发完成并开源,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。是现在比较主流的存储格式。
Parquet文件是以二进制方式存储的,是不可以直接读取和修改的,Parquet文件是自解析的,文件中包括该文件的数据和元数据。在HDFS文件系统和Parquet文件中存在如下几个概念:
a、HDFS块(Block):它是HDFS上的最小的副本单位,HDFS会把一个Block存储在本地的一个文件并且维护分散在不同的机器上的多个副本,通常情况下一个Block的大小为256M、512M等。
b、HDFS文件(File):一个HDFS的文件,包括数据和元数据,数据分散存储在多个Block中。
c、行组(Row Group):按照行将数据物理上划分为多个单元,每一个行组包含一定的行数,在一个HDFS文件中至少存储一个行组,Parquet读写的时候会将整个行组缓存在内存中,所以如果每一个行组的大小是由内存大的小决定的。
d、列块(Column Chunk):在一个行组中每一列保存在一个列块中,行组中的所有列连续的存储在这个行组文件中。不同的列块可能使用不同的算法进行压缩。
e、页(Page):每一个列块划分为多个页,一个页是最小的编码的单位,在同一个列块的不同页可能使用不同的编码方式。
6、 INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname
这个类型的意思指的是我们在创建hive表的时候,可以指定INPUTFORMAT 和OUTPUTFORMAT 的类型。下面我将演示一下这个参数的用法。
我们先在hive上创建一张很简单表,后面的参数都用默认格式。创建成功后,我们来查看一下这张表指定的INPUTFORMAT 和OUTPUTFORMAT 的值。
hive (default)> create table t1(id int);
OK
Time taken: 0.306 seconds
hive (default)> desc formatted t1;
OK
# col_name data_type comment
id int
# Detailed Table Information
Database: default
Owner: hadoop
CreateTime: Tue Dec 11 11:19:43 CST 2018
LastAccessTime: UNKNOWN
Protect Mode: None
Retention: 0
Location: hdfs://hadoop001:9000/user/hive/warehouse/t1
Table Type: MANAGED_TABLE
Table Parameters:
transient_lastDdlTime 1544498383
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params:
serialization.format 1
Time taken: 0.149 seconds, Fetched: 26 row(s)
hive (default)>
可以看到InputFormat的值为org.apache.hadoop.mapred.TextInputFormat,OutputFormat的值为org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat。
我们在建表的时候,可以直接指定这个两个参数,我们再建一张表t2。
hive (default)> create table t2(id int) stored as InputFormat 'org.apache.hadoop.mapred.TextInputFormat' OutputFormat 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat';
OK
Time taken: 0.069 seconds
hive (default)> desc formatted t2;
OK
# col_name data_type comment
id int
# Detailed Table Information
Database: default
Owner: hadoop
CreateTime: Tue Dec 11 11:24:40 CST 2018
LastAccessTime: UNKNOWN
Protect Mode: None
Retention: 0
Location: hdfs://hadoop001:9000/user/hive/warehouse/t2
Table Type: MANAGED_TABLE
Table Parameters:
transient_lastDdlTime 1544498680
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params:
serialization.format 1
Time taken: 0.051 seconds, Fetched: 26 row(s)
hive (default)>
我们可以根据需要选择InputFormat和OutputFormat的值,这里只是做一个简单的演示。