这是我参与「第四届青训营」笔记创作活动的第13天。
1. 列式存储和行式存储的区别
数据格式层
- 计算层:各种计算引擎
- 存储层:承载数据的持久化存储
- 数据格式层:定义了存储层文件内部的组织格式,计算引擎通过格式层的支持来读写文件 严格意义上,并不是一个独立的层级,而是运行在计算层的一个Library。
OLTP vs OLAP
- OLTP 行式存储格式
-
每一行 (Row) 的数据在文件的数据空间里连续存放的
-
读取整行的效率比较高,一次顺序 IO 即可
-
在典型的 OLTP 型的分析和存储系统中应用广泛,例如:MySQL、Oracle、RocksDB 等
-
- OLAP 列式存储格式
-
每一列 (Column) 的数据在文件的数据空间里连续存放的
-
同列的数据类型一致,压缩编码的效率更好
-
在典型的 OLAP 型分析和存储系统中广泛应用,例如:大数据分析系统:Hive、Spark,数据湖分析数据仓库:ClickHouse,Greenplum,阿里云 MaxCompute
-
- 两者比较
- OLTP 和 OLAP 作为数据查询和分析领域两个典型的系统类型,具有不同的业务特征,适配不同的业务场景。理解两者的区别可以帮助更好的理解行存和列存的设计背景
2. Parquet 列存格式的原理详解
parquet
Parquet 是一种能够有效存储嵌套数据的列存储格式。(列式存储格式在文件大小和查询性能上表现优秀) Parquet 的突出贡献在于能够以真正的列式存储格式来保存具有深度嵌套结构的数据。
数据模型
-
Protocol Buffer 定义
-
支持可选和重复字段
-
支持嵌套类型
数据文件布局
-
RowGroup: 每一个行组包含一定数量或者固定大小的行的集合,在 HDFS 上,RowGroup 大小建议配置成 HDFS Block 大小
-
ColumnChunk: RowGroup 中按照列切分成多个 ColumnChunk
-
Page:ColumnChunk内部继续切分成 Page,一般建议 8KB 大小。Page 是压缩和编码的基本单元。根据保存的数据类型,Page 可以分为:Data Page,Dictionary Page,Index Page
-
Footer 保存文件的元信息
- Schema、Config、 Metadata
编码
在 Parquet 的 ColumnChunk 里,同一个 ColumnChunk 内部的数据都是同一个类型的,可以通过编码的方式更高效的存储。
- Run Length Encoding (RLE):适用于列基数不大,重复值较多的场景,如枚举、固定的选项等
-
Bit-Pack Encoding: 对于 32位或者64位的整型数而言,并不需要完整的 4B 或者 8B 去存储,高位的零在存储时可以省略掉。适用于最大值非常明确的情况下。
-
Dictionary Encoding:适用于列基数 (Column) 不大的字符串类型数据存储。
压缩
完成 Encoding 以后,进行压缩。支持多种压缩算法。
- snappy: 压缩速度快,压缩比不高,适用于热数据
- gzip:压缩速度慢,压缩比高,适用于冷数据
- zstd:新引入的压缩算法,压缩比和 gzip 差不多,而且压缩速度略低于 Snappy
索引
和传统的数据库相比,索引支持非常简陋
-
Min-Max Index :记录 Page 内 Column 的 min_value 和 max_value
-
Column Index :Footer 里的 Column Metadata 包含 ColumnChunk 的全部 Page 的 Min-Max Value
-
Offset Index:记录 Page 文件中的 offset 和 row range.
总结
列式存储格式在文件大小和查询性能上表现优秀。OLTP 和 OLAP 作为数据查询和分析领域两个典型的系统类型,具有不同的业务特征,适配不同的业务场景。Parquet 是一种能够有效存储嵌套数据的列存储格式。