以前据说 RCFile 在读取数据时能够跳过不须要的列,不须要将一整行读入而后选择所需字段,因此在 Hive 中执行 select a, b from tableA where c = 1
这样的操做就相对比较高效。为了知足好奇心,找了一下关于 RCFile 的论文(RCFile: A Fast and Space-efficient Data Placement Structure in MapReduce-based Warehouse System)看了一下,这里记录一下看成笔记。html
首先大数据的查询和处理有如下几个需求:数据库
在传统的数据库系统中,主要有三种数据存储方式:缓存
水平的行存储结构: 行存储模式就是把一整行存在一块儿,包含全部的列,这是最多见的模式。这种结构能很好的适应动态的查询,好比 select a from tableA
和 select a, b, c, d, e, f, g from tableA
这样两个查询其实查询的开销差很少,都须要把全部的行读进来过一遍,拿出须要的列。并且这种状况下,属于同一行的数据都在同一个 HDFS 块上,重建一行数据的成本比较低。可是这样作有两个主要的弱点:a)当一行中有不少列,而咱们只须要其中不多的几列时,咱们也不得不把一行中全部的列读进来,而后从中取出一些列。这样大大下降了查询执行的效率。b)基于多个列作压缩时,因为不一样的列数据类型和取值范围不一样,压缩比不会过高。网络
垂直的列存储结构: 列存储是将每列单独存储或者将某几个列做为列组存在一块儿。列存储在执行查询时能够避免读取没必要要的列。并且通常同列的数据类型一致,取值范围相对多列混合更小,在这种状况下压缩数据能达到比较高的压缩比。可是这种结构在重建出行时比较费劲,尤为适当一行的多个列不在一个 HDFS 块上的时候。 好比咱们从第一个 DataNode 上拿到 column A,从第二个 DataNode 上拿到了 column B,又从第三个 DataNode 上拿到了 column C,当要把 A,B,C 拼成一行时,就须要把这三个列放到一块儿重建出行,须要比较大的网络开销和运算开销。布局
混合的 PAX 存储结构: PAX 结构是将行存储和列存储混合使用的一种结构,主要是传统数据库中提升 CPU 缓存利用率的一种方法,并不能直接用到 HDFS 中。可是 RCFile 也是继承自它的思想,先按行存再按列存。post
<!--more-->大数据
数据的布局: 首先根据 HDFS 的结构,一个表能够由多个 HDFS 块构成。在每一个 HDFS 块中,RCFile 以 row group 为基本单位组织数据,一个表多全部 row group 大小一致,一个 HDFS 块中能够包含多个 row group。每一个 row group 包含三个部分,第一部分是 sync marker,用来区分一个 HDFS 块中两个连续多 row group。第二部分是 row group 的 metadata header,记录每一个 row group 中有多少行数据,每一个列数据有多少字节,以及每列一行数据的字节数。第三部分就是 row group 中的实际数据,这里是按列存储的。优化
数据的压缩: 在 metadata header 部分用 RLE (Run Length Encoding) 方法压缩,由于对于记录每一个列数据中一行数据的字节数是同样的,这些数字重复连续出现,所以用这种方法压缩比比较高。在压缩实际数据时,每列单独压缩。编码
数据的追加写: RCFile 会在内存里维护每一个列的数据,叫 column holder,当一条记录加入时,首先会被打散成多个列,人后追加到每列对应的 column holder,同时更新 metadata header 部分。能够经过记录数或者缓冲区大小控制内存中 column holder 的大小。当记录数或缓冲大小超过限制,就会先压缩 metadata header,再压缩 column holder,而后写到 HDFS。设计
数据的读取和惰性解压(lazy decompression): RCFile 在处理一个 row group 时,只会读取 metadata header 和须要的列,合理利用列存储在 I/O 方面的优点。并且即便在查询中出现的列技术读进内存也不必定会被解压缩,只有但肯定该列数据须要用时才会去解压,也就是惰性解压(lazy decompression)。例如对于 select a from tableA where b = 1
,会先解压 b 列,若是对于整个 row group 中的 b 列,值都不为 1,那么就不必对这个 row group 对 a 列去解压,由于整个 row group 都跳过了。
row group 的大小: row group 过小确定是不能充分发挥列存储的优点,可是太大也会有问题。首先,论文中实验指出,当 row group 超过某一阈值时,很难再得到更高当压缩比。其次,row group 太大会下降 lazy decompression 带来的益处,仍是拿 select a from tableA where b = 1
来讲,若是一个 row group 里有一行 b = 1
,咱们仍是要解压 a 列,从而根据 metadata header 中的信息找到 b = 1
的那行的 a 列的值,若是此时咱们把 row group 设小一点,假设就设成 1,这样对于 b <> 1
的行都不须要解压 a 列。最后论文中给出一个通常性的建议,建议将 row group 设成 4MB。
而后是 ORC File(Optimized Row Columnar file),对RCFile作了一些优化,克服 RCFile 的一些限制,主要参考这篇文档。 和RCFile格式相比,ORC File格式有如下优势:
ORC File包含一组组的行数据,称为stripes,除此以外,ORC File的file footer还包含一些额外的辅助信息。在ORC File文件的最后,有一个被称为postscript的区,它主要是用来存储压缩参数及压缩页脚的大小。
在默认状况下,一个stripe的大小为250MB。大尺寸的stripes使得从HDFS读数据更高效。
在file footer里面包含了该ORC File文件中stripes的信息,每一个stripe中有多少行,以及每列的数据类型。固然,它里面还包含了列级别的一些聚合的结果,好比:count, min, max, and sum。这里贴一下文档上的图:
每一个Stripe都包含index data、row data以及stripe footer,Stripe footer包含流位置的目录,Row data在表扫描的时候会用到。
Index data包含每列的最大和最小值以及每列所在的行。行索引里面提供了偏移量,它能够跳到正确的压缩块位置。
经过行索引,能够在stripe中快速读取的过程当中能够跳过不少行,尽管这个stripe的大小很大。在默认状况下,最大能够跳过10000行。
由于能够经过过滤预测跳过不少行,于是能够在表的 secondary keys 进行排序,从而能够大幅减小执行时间。好比你的表的主分区是交易日期,那么你能够对次分区(state、zip code以及last name)进行排序。