在新建Hive表时,可使用stored as rcfile来指定hive文件的存储方式为RCFile。算法
下图是一个RCFile的文件结构形式。
从上图能够看出:
1)一张表能够包含多个HDFS block。
2)在每一个block中,RCFile以行组(row group,相似于ORC中的stripe)为单位存储其中的数据。所谓行组是指在关系型数据块中,若干条记录组成的一个group。对于一张表来讲,row group的大小是固定的。经过HDFS的block大小和row group的大小,可以肯定一个block上能够容纳多少个row group。
3)row group又由三个部分组成,包括一个用于在block中分隔两个row group的16字节的标志区,一个存储row group元数据信息的header,以及实际数据区。表中的实际数据以列为单位进行存储。sql
在存储RCFile时,会对每一个row group的metadata header区和data区进行压缩。
在metadata header区中,记录了该row group中有多少记录,每一个column总共有多少字节数,以及每一个column中每个field的字节数等信息。对metadata header区,使用RLE(Run Length Encoding)算法来压缩数据。须要读取指定column的记录时,能够根据这个metadata中记录的字节数等信息,很快定位到对应的数据。
对data区的数据压缩时,RCFile文件格式并不会将整个区域一块儿进行压缩,而是以列为单位进行Gzip压缩,这样的处理方式使得须要读取某些指定列的数据时,其余无关的列不须要进行读取。
markdown
因为目前HDFS只支持在文件末尾追加内容,没法随意修改hdfs文件中的数据。因此在使用RCFile文件的hive表中也只能在文件末尾写入新的记录。在向RCFile写入数据时,
(1)为了不频繁的写入操做,RCFile会为每个column在内存中维持一个对应的column holder。当有记录插入到hive表中时,会把这一条记录的每一个字段拆散存入到对应的column holder的末尾。伴随着这个操做的同时,会在metadata header中记录这次操做的相关信息。
(2)上面的column holder固然是不能无限大的,为此RCFile设定了两个参数,当知足任何一个时,就会把column holder中的数据flush到磁盘上。这两个参数一个是写入记录数,另外一个是column holder使用的内存大小。
(3)记录写入完毕后,RCFile首先会将metadata header进行压缩。而后把每个column单独进行压缩,最后将压缩好的数据flush到同一个row group中。性能
当须要从一个row group读取数据时,RCFile并不会将整个row group中的数据都读入到内存中,须要读入的数据只包括metadata header,以及在语句中指定的那些column。
这两部分数据读入到内存中后,首先会将metadata header进行解压缩,并一直保存在内存中。接下来对加载到内存中的column数据,在RCFile中有一个lazy decompression的概念,这个的意思是说,column数据并不会在加载到内存中后立刻进行解压缩,而是后续处理中的确须要读取这个column数据时解压缩过程才会执行。好比有一个sql语句,select a,b,c from table where a > 5;
首先会对字段a解压缩,若是判断全部记录中没有a > 5的记录,那么字段b和字段c都没必要要进行解压缩了。
code
参数 | 默认值 | 描述 |
---|---|---|
hive.io.rcfile.record.buffer.size | 4194304 | 设置row group的大小 |
hive.io.rcfile.record.interval | 2147483647 | row group中最大记录数 |
row group默认大小为4MB主要是由于row group不能太大,也不能过小。在Gzip压缩算法中,增大row group的大小可以提高压缩的性能。可是当row group的大小达到某个阈值时,继续增大row group并不能带来压缩性能的提高。而且,以上面的sql语句为例若是一个row group越大,其中保存的记录也就越多,这样该row group中出现a >5的记录的几率就越大,那么就越难使用到lazy decompression这一特性带来的性能提高。而且row group越大,消耗的内存也就越多。
这个大小限制在ORC文件格式中获得了改善。
ip