存储格式在Hive的应用

介绍

  • 存储按存储方式的不同可分为两类,一是行式存储,二是列式存储,对相同的原文件使用不同的存储格式可以减少不等的存储空间,并且在读取相同的原文件时,拉取的数据量会有较大差别,这样会减少磁盘的IO,从而缩短任务消耗的时间。存储一般会配合压缩一起使用,这样可以进一步减少存储空间和磁盘IO。
  • 行式存储:
    优点,一行记录的所有字段可以存储在同一个block中,这样在查询所有字段信息时可以直接获取。
    缺点,由于一行记录的所有字段数据类型不尽相同,所有压缩性能较低,并且在查询特定字段信息时,需要获取所有字段信息,这样会增加网络的IO

  • 列式存储:
    优点,按列存储的每一列的数据类型相同,压缩性能较好,在查询特定字段信息时可以直接拉取需要信息,减少读取不必要的信息
    缺点,行的重组性能较低。

Hive中的存储格式

  • 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)
    | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname

TEXTFILE:文本文件

  • 存储方式:行存储
  • 默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
  • 创建方式:
    textfile格式为hive中默认格式,创建方式可以有三种
    方式一

    1. CREATE TABLE tt (
    2. id int,
    3. name string
    4. ) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
    

方式二

    1. CREATE TABLE tt2 (
    2. id int,
    3. name string
    4. ) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    5. STORED AS TEXTFILE;

方式三:

    1. CREATE TABLE tt3 (
    2. id int,
    3. name string
    4. ) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    5. STORED AS 
    6. INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
    7. OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'; #存储格式的底层方法

Sequencefile:二进制文件

  • 存储说明
    这里写图片描述
    Record:存储SequenceFile通用的KV数据格式,Key和Value都是二进制变长的数据。Record表示Key和Value的byte的总和。
    Sync:主要是用来扫描和恢复数据的,以至于读取数据的Reader不会迷失。
    Header:存储了如下信息:文件标识符SEQ,key和value的格式说明,以及压缩的相关信息,metadata等信息。
    metadata:包含文件头所需要的数据:文件标识、Sync标识、数据格式说明(含压缩)、文件元数据(时间、owner、权限等)、检验信息等。

  • 存储方式:行存储;

  • SequenceFile是Hadoop API 提供的一种二进制文件,它将数据(key,value)的形式序列化到文件里。这样的二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。
    Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,只是它的key为空。使用value 存放实际的值。 这样是为了避免MR 在执行map 阶段的排序过程。
  • SEQUENCEFILE比TextFile 多了一些冗余信息,所以要大一些。
  • 创建Sequencefile表并与textfile比较

    1. create table page_views_seq(
    2. track_time string,
    3. url string,
    4. session_id string,
    5. referer string,
    6. ip string,
    7. end_user_id string,
    8. city_id string
    9. )ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    10. STORED AS SEQUENCEFILE;
    

    load textfile格式文件进入到sequencefile表并不可行,这时需要使用insert 语句

    1. insert into table page_views_seq select * from page_views; 
    

    文件大小比较

    1. TextFile存储格式的大小
    2. [hadoop@hadoop ~]$ hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views
    3. 18.1 M   /user/hive/warehouse/hive.db/page_views
    4. SEQUENCEFILE存储格式的大小
    5. [hadoop@hadoop ~]$ hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views_seq 
    6. 19.6 M   /user/hive/warehouse/hive.db/page_views_seq
    7. 原始大小
    8. [hadoop@hadoop ~]$ du -sh data/page_views.dat
    9. 19M     data/page_views.dat
    

Rcfile

  • 存储说明
    这里写图片描述
    这个架构是利用了先行式存储再列式存储的方式。在每个row group中为列式存储,相对于sequenceFile的大小,有一定优势,大概比textFile小10%。
    当查询过程中,针对它并不关心的列时,它会在IO上跳过这些列。须要说明的是。RCFile在map阶段从远端拷贝仍然是拷贝整个数据块,而且复制到本地文件夹后,RCFile并非真正直接跳过不须要的列,并跳到须要读取的列, 而是通过扫描每个row group的头部定义来实现的。
    可是在整个HDFS Block 级别的头部并未定义每个列从哪个row group起始到哪个row group结束。所以在读取全部列的情况下。RCFile的性能反而没有SequenceFile高。

  • 创建并比较

    1. create table page_views_rcfile(
    2. track_time string,
    3. url string,
    4. session_id string,
    5. referer string,
    6. ip string,
    7. end_user_id string,
    8. city_id string
    9. )ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    10. STORED AS RCFILE;
    

    插入数据:

    1. insert into table page_views_rcfile select * from page_views;
    

    查看大小:

    1. hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views_rcfile
    2. 17.9 M  /user/hive/warehouse/hive.db/page_views_rcfile
    

ORC

  • 存储说明
    这里写图片描述

ORC文件:保存在文件系统上的普通二进制文件,一个ORC文件中可以包含多个stripe,每一个stripe包含多条记录,这些记录按照列进行独立存储,对应到Parquet中的row group的概念。
文件级元数据:包括文件的描述信息PostScript、文件meta信息(包括整个文件的统计信息)、所有stripe的信息和文件schema信息。
stripe:一组行形成一个stripe,每次读取文件是以行组为单位的,一般为HDFS的块大小,保存了每一列的索引和数据。
stripe元数据:保存stripe的位置、每一个列的在该stripe的统计信息以及所有的stream类型和位置。
row group:索引的最小单位,一个stripe中包含多个row group,默认为10000个值组成。
stream:一个stream表示文件中一段有效的数据,包括索引和数据两类。索引stream保存每一个row group的位置和统计信息,数据stream包括多种类型的数据,具体需要哪几种是由该列类型和编码方式决定。

  • ORC 简介
    ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式,它的产生早在2013年初,最初产生自Apache Hive,用于降低Hadoop数据存储空间和加速Hive查询速度。和Parquet类似,它并不是一个单纯的列式存储格式,仍然是首先根据行组分割整个表,在每一个行组内进行按列存储。ORC文件是自描述的,它的元数据使用Protocol Buffers序列化,并且文件中的数据尽可能的压缩以降低存储空间的消耗,目前也被Spark SQL、Presto等查询引擎支持,但是Impala对于ORC目前没有支持,仍然使用Parquet作为主要的列式存储格式。2015年ORC项目被Apache项目基金会提升为Apache顶级项目。ORC具有以下一些优势:

    1. ORC是列式存储,有多种文件压缩方式,并且有着很高的压缩比。
    2. 文件是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅节省HDFS存储资源,查询任务的输入数据量减少,使用的MapTask也就减少了。
    3. 提供了多种索引,row group index、bloom filter index。
    4. ORC可以支持复杂的数据结构(比如Map等)
  • ORC文件读取

    1. 读取ORC文件是从尾部开始的,第一次读取16KB的大小,尽可能的将Postscript和Footer数据都读入内存。文件的最后一个字节保存着PostScript的长度,它的长度不会超过256字节,PostScript中保存着整个文件的元数据信息,它包括文件的压缩格式、文件内部每一个压缩块的最大长度(每次分配内存的大小)、Footer长度,以及一些版本信息。在Postscript和Footer之间存储着整个文件的统计信息(上图中未画出),这部分的统计信息包括每一个stripe中每一列的信息,主要统计成员数、最大值、最小值、是否有空值等。

    2. 接下来读取文件的Footer信息,它包含了每一个stripe的长度和偏移量,该文件的schema信息(将schema树按照schema中的编号保存在数组中)、整个文件的统计信息以及每一个row group的行数。

    3. 处理stripe时首先从Footer中获取每一个stripe的其实位置和长度、每一个stripe的Footer数据(元数据,记录了index和data的的长度),整个striper被分为index和data两部分,stripe内部是按照row group进行分块的(每一个row group中多少条记录在文件的Footer中存储),row group内部按列存储。每一个row group由多个stream保存数据和索引信息。每一个stream的数据会根据该列的类型使用特定的压缩算法保存。

  • 几种创建ORC格式的方式

    1. CREATE TABLE ... STORED AS ORC
    2. ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT ORC 
    3. SET hive.default.fileformat=Orc
    
  • 修改ORC格式参数可在HQL语句中的TBLPROPERTIES字段以key-value方式修改
    这里写图片描述
    总结: ORC能很大程序的节省存储和计算资源,但它在读写时候需要消耗额外的CPU资源来压缩和解压缩,当然这部分的CPU消耗是非常少的。
    对性能提升的另一个方面是通过在ORC文件中为每一个字段建立一个轻量级的索引,来判定一个文件中是否满足WHERE子句中的过滤条件。比如:当执行HQL语句”SELECT COUNT(1) FROM lxw1234_orc WHERE id = 0”时候,先从ORC文件的metadata中读取索引信息,快速定位到id=0所在的offsets,如果从索引信息中没有发现id=0的信息,则直接跳过该文件。

  • ORC的压缩比
    这里写图片描述

  • 创建ORC格式表

    1. create table page_views_orc_zlib
    2. ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    3. STORED AS ORC 
    4. TBLPROPERTIES("orc.compress"="ZLIB")
    5. as select * from page_views;
    
    6. [hadoop@hadoop ~]$ hdfs dfs -du -s -h /user/hive/warehouse/hive.db/page_views_orc_zlib
    7. 2.8 M  /user/hive/warehouse/hive.db/page_views_orc_zlib
    

Parquet

  • Parquet 存储格式现在为apache一个顶级项目,它可以使用在hadoop 生态的大多数软件中。
  • parquet 使用列式存储,其性能可以个ORC比肩,可支持多种压缩技术。

  • 创建parquet格式表

    1. create table page_views_parquet
    2. ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    3. STORED AS PARQUET 
    4. as select * from page_views;
    

使用Bzip2压缩

    1. set parquet.compression=gzip;
    2. create table page_views_parquet_gzip
    3. ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
    4. STORED AS PARQUET 
    5. as select * from page_views;

猜你喜欢

转载自blog.csdn.net/Realoyou/article/details/79548137