行式存储
特点:
保证一条记录里面的所有字段能够存放在同一个hdfs的block里
优点:
当查询所有(select * from tbname)时,能直接查询出来
缺点:
不同列的字段类型不同,压缩性能差,空间利用率差
只查询某几列数据的时候,必须先把所有数据读取进来,在提取所需的几列,结果会增加磁盘IO,效率低
列式存储
优点:
每一列的数据类型是一样的,所有可以采用一定压缩方式,压缩性能好
只查询某几列数据的时候,对于不需要的列,可以直接跳过
缺点:
当查询所有(select * from tbname)时,对于行的数据必然会重组
TEXTFILE格式
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
SequenceFile(行式存储)
类似于二进制,是key-value存储的
压缩只能压缩value,对比于TestFile,多了一些冗余信息,但是随机读写要好一些
ORC格式(列式存储)
Orc (Optimized Row Columnar)是hive 0.11版里引入的新的存储格式。
可以看到每个Orc文件由1个或多个stripe组成,每个stripe250MB大小,这个Stripe实际相当于RowGroup概念,不过大小由4MB->250MB,这样能提升顺序读的吞吐率。每个Stripe里有三部分组成,分别是Index Data,Row Data,Stripe Footer:
一个orc文件可以分为若干个Stripe
一个stripe可以分为三个部分
indexData:某些列的索引数据
rowData :真正的数据存储
StripFooter:stripe的元数据信息
1)Index Data:一个轻量级的index,默认是每隔1W行做一个索引。这里做的索引只是记录某行的各字段在Row Data中的offset。
2)Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个Stream来存储。
3)Stripe Footer:存的是各个stripe的元数据信息
每个文件有一个File Footer,这里面存的是每个Stripe的行数,每个Column的数据类型信息等;每个文件的尾部是一个PostScript,这里面记录了整个文件的压缩类型以及FileFooter的长度信息等。在读取文件时,会seek到文件尾部读PostScript,从里面解析到File Footer长度,再读FileFooter,从里面解析到各个Stripe信息,再读各个Stripe,即从后往前读。
PARQUET格式(列式存储)
Parquet是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。
Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
通常情况下,在存储Parquet数据的时候会按照Block大小设置行组的大小,由于一般情况下每一个Mapper任务处理数据的最小单位是一个Block,这样可以把每一个行组由一个Mapper任务处理,增大任务执行并行度。Parquet文件的格式如下图所示。
上图展示了一个Parquet文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的Magic Code,用于校验它是否是一个Parquet文件,Footer length记录了文件元数据的大小,通过该值和文件长度可以计算出元数据的偏移量,文件的元数据中包括每一个行组的元数据信息和该文件存储数据的Schema信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在Parquet中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字典页,索引页用来存储当前行组下该列的索引,目前Parquet中还不支持索引页。
数据准备:
create table page_views(
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';
load data local inpath '/home/hadoop/data/page_views.dat'overwrite into table page_views;
## page_views 18.1m
开启hive压缩功能
SET hive.exec.compress.output=true;## 在hive输出写入表时进行压缩
set mapreduce.output.fileoutputformat.compress.codec=BZip2Codec;## 这里先使用BZIP2
jdbc:hive2://hadoop-01:10000> create table page_views_bzip2 as select * from page_views;
[hadoop@hadoop-01 ~]#hdfs dfs -du -s -h /user/hive/warehouse/g6_hive_416.db/page_views_bzip2
3.6 M 10.9 M /user/hive/warehouse/g6_hive_416.db/page_views_bzip2
数据明显小了。
在hive的建表语句中在row format 后是有[STORED AS file_format]
### sequencefile
create table page_views_seq(
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'
stored as sequencefile;
insert into table page_views_seq select * from page_views;
[hadoop@hadoop-01 ~]hdfs dfs -du -s -h /user/hive/warehouse/g6_hive_416.db/page_views_seq
20.6 M 61.8 M /user/hive/warehouse/g6_hive_416.db/page_views_seq
所以sequencefile 文件太大了,一般不用
### rcfile
进行相同的操作后,rcfile 的大小为17.9,仅作为存储节省了大约10%的空间。
###orcfile
create table page_views_orc(
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'
stored as orc ;
insert into table page_views_orc select * from page_views;
[hadoop@hadoop-01 ~]hdfs dfs -du -s -h /user/hive/warehouse/g6_hive_416.db/page_views_orc
2.8 M 8.4M /user/hive/warehouse/g6_hive_416.db/page_views_orc
文件为2.8M是因为底层默认使用了ZLIB压缩,orc文件支持snappy,zlib和none。
### 使用orc存储不压缩
create table page_views_orc_none
stored as orc tblproperties ("orc.compress"="NONE")
as select * from page_views;
[hadoop@hadoop-01 ~]hdfs dfs -du -s -h /user/hive/warehouse/g6_hive_416.db/page_views_orc_none
7.7 M 23.1M /user/hive/warehouse/g6_hive_416.db/page_views_orc_none
所以用orcfile存储,即使不压缩,也能从18.1m==>7.7m
#### 使用parquet
set parquet.compression=gzip; !!!### parquet设置压缩的方式比较特别
create table page_views_parquet_gzip
stored as parquet
as select * from page_views;
存储压缩后的大小为3.9M,也是一个不错的选择
当查询某条记录时,查询普通表时,用了全表扫描(19022735);查询rc表稍少了点(3725393);查询orc表时,就小了很多了(1257513)。