列式存储与传统的行式存储异同及优势
行式存储可以看成是一个行的集合,其中每一行都要求对齐,哪怕某个字段为空(下图中的左半部分),而列式存储则可以看成一个列的集合(下图中的右半部分)。列式存储的优点很明显,主要有以下 4 点:
- 查询时可以只读取涉及的列(选择操作),并且列可以直接作为索引,非常高效,而行式存储则必须读入整行。
- 列式存储的投影操作非常高效。
- 在数据稀疏的情况下,压缩率比行式存储高很多,甚至可以考虑将相关的表进行预先连接,来完全避免投影操作。
- 因为可以直接作用于某一列上,聚合分析非常迅速。
- 行式存储一般擅长的是插入与更新操作,而列式存储一般适用于数据为只读的场景。对于结构化数据,列式存储并不陌生。因此,列式存储技术经常用于传统数据仓库中。
下图分别展示了行式存储和列式存储的区别。
列式存储的实现
Apache Parquet
Apache Parquet 是 Dremel 的开源实现,它最先是由 Twitter 与 Cloudera 合作开发并开源,和 Impala 配合使用。Parquet 支持几乎 Hadoop 生态圈的所有项目,与数据处理框架、数据结构以及编程语言无关。
Apache ORC
Apache ORC(OptimizedRC file)来源于 RC(RecordColumnar file)格式,但目前已基本取代 RC 格式。ORC 提供 ACID 支持、也提供不同级别的索引,如布隆过滤器、列统计信息(数量、最值等),和 Parquet 一样,它也是自描述的数据格式,但与 Parquet 不同的是,ORC 支持多种复杂数据结构,如集合、映射等。ORC 与 Presto 配合使用,效果非常好。
Apache CarbonData
CarbonData 是华为开源的一种列式存储格式,是专门为海量数据分析和处理而生的。CarbonData 于 2016 年开源,目前发展非常迅猛,与 Apache Kylin 并列为由国人主导的两个Apache *项目。它的设计初衷源于,在很多时候,对于同样一份数据,处理方式是不同的,比如以下几种处理方式:
全表扫描,或者选取几列进行过滤;
随机访问,如行键值查询,要求低延迟;
ad-hoc 交互式分析,如多维聚合分析、上卷、下钻、切片等。
不同的处理方式对于数据格式的需求侧重点是不同的,但 CarbonData 旨在为大数据多样化的分析需求提供一种统一的数据格式。CarbonData 的设计目标为:
支持低延迟访问多种数据访问类型;
允许在压缩编码过的数据上进行快速查询;
确保存储空间的高效性;
很好地支持 Hadoop 生态系统;
读最优化的列式存储;
利用多级索引实现低延迟;
支持利用列组来获得基于行的优点;
能够对聚合的延迟解码进行字典编码。
如下图所示,这是一个 CarbonData 数据文件,也是 HDFS 上的一个数据块,每个文件由 File Header、File Footer 与若干个 Blocklet 组成,其中 File Header 保存了文件版本号、Schema 以及更新时间戳;File Footer 包含了一些统计信息(每个 Blocklet 的最值)、多维索引等。一个 Blocklet 的默认大小为 64MB,包含多个 Column Page Group,Blocklet 可以看成一个表的水平切片,这个表有多少列,就有多少个 Column Page Group,在一个 Column Page Group 中,一列被分为若干个连续文件,每一个文件被称为 Page,一个 Page 默认为 32000 行,如下图所示。
CarbonData 在设计理念上没有采取 Dremel 提出的嵌套的列式存储,而是引入了索引和元数据的设计,但仍然属于列式存储格式。ORC 的压缩率最高,而 CarbonData 在 Spark 批处理这种场景下,性能表现得非常好,是一种非常有前景的技术。
列式存储的压缩率如此之高,从本课时的第一张图也可以看出原因,列式存储作为列的集合,空间几乎没有多余的浪费。如此高的压缩效率也带来了一个优化思路:可以将若干相关的表预先进行连接,连接而成的表可以看成是一张稀疏的宽表,这张宽表对分析来说就非常友好了,但由于采用了列式存储,所以宽表所占的空间并不是指数上涨而是线性增加。在这种场景下,列式存储使得空间换时间成为可能。