Parquet 和 ORC|青训营笔记

308 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第19天

本次笔记重点内容

  1. 列式存储和行式存储
  2. Parquet 列存格式的原理
  3. ORC 列存格式的原理以及和Parquet 的对比
  4. 列存格式的演进

数据格式层

  • 计算层:各种计算引擎,Rows+Columns
  • 存储层:承载数据的持久化存储,File/Blocks
  • 格式层:定义了存储层文件内部组织格式,高效读取文件,连接计算引擎和存储服务,Layout+Schema

image.png

OLTP && OLAP

image.png

OLTP——行式存储格式

每行数据在文件上是连续存储的,读取整行数据效率高——单次IO顺序读即可

image.png

应用场景:在典型的 OLTP 型的分析和存储系统中应用广泛,例如MySQL、Oracle等

OLAP——列式存储格式

每列数据在文件上是连续存储的,读取整列数据效率高,同列的数据类型一致

image.png

应用场景:在典型的 OLAP 型分析和存储系统中广泛应用,例如Hive、Spark、数据湖分析等

Parquet

大数据分析领域使用最广的列式存储,Spark广泛应用的存储格式

Parquet && 普通文本格式

image.png

Parquet存储格式小,Text大很多

Parquet数据模型

依据 Dremel 数据模型

image.png

构建语法树,嵌套类型只保存叶子节点数据格式。

数据文件布局
  • RowGroup: 每一个行组包含一定数量或者固定大小的行的集合(在 HDFS 上,RowGroup 大小建议配置成 HDFS Block 大小)
  • ColumnChunk: RowGroup 中按照列切分成多个 ColumnChunk
  • Page:ColumnChunk内部继续切分成 Page,Page 是压缩和编码的基本单元。根据保存的数据类型,Page 可以分为:Data Page、Dictionary Page、Index Page
  • Footer 保存文件的元信息
    • Schema
    • Config
    • Metadata
数据编码
  • Plain直接存储原始数据
  • Run Length Encoding(RLE)

image.png

  • Dictionary Encoding 字典编码

image.png

构造字典表,用字典中的 Index 替换真实数据,替换后的数据可以使用 RLE + Bit-Pack 编码存储

压缩方式
  • snappy: 压缩速度快,压缩比不高,适用于热数据
  • gzip:压缩速度慢,压缩比高,适用于冷数据
  • zstd:新引入的压缩算法,压缩比和 gzip 差不多,压缩速度略低于 Snappy
索引 Index

和传统的数据库相比,索引支持非常简陋,主要依赖 Min-Max Index 和排序来加速查找。

  • Page:记录 Column 的 min_value 和 max_value
  • Footer 里的 Column Metadata 包含 ColumnChunk 的全部 Page 的 Min-Max Value

Bloom Filter 过滤器

对于列基数比较大的场景,或者非排序列的过滤,引入 Bloom Filter 加速过滤匹配判定

排序 Ordering

聚集索引的概念,帮助更好的过滤掉无关的RowGroup或Page

过滤下推Predicate PushDown

高效过滤机制,在格式层过滤掉大多数不相关的数据,减少真实的读取数据量

image.png

Spark集成——向量化读

向量化读是主流大数据引擎的标准实践,极大提升了查询性能。Spark以Batch的方式从 Parquet 读取数据,下推的逻辑也会适配 Batch 的方式

ORC

大数据分析领域使用最广的列存格式之一,出自Hive项目

数据模型

image.png

ORC 会给包括根节点在内的中间节点都创建一个 Column,嵌套类型或者集合类型支持和 Parquet 差别较大,optional 和 repeated 字段依赖父节点记录额外信息来重新 Assembly 数据

数据布局

类似Parquet,Encoding / Compression / Index 支持上和 Parquet 几乎一致

AliORC

索引增强

支持 Clusterd Index,更快的主键查找;支持 Bitmap Index,更快的过滤

小列聚合——减少小IO

重排Chunk——把小的列放到一起,方便读取

image.png

异步预取

在计算引擎处理已经读到的数据的时候,异步去预取下一批次数据,计算逻辑和数据读取并行化

Parquet VS ORC

  • 从原理层面,最大的差别就是对于 NestedType 和复杂类型处理上
  • Parquet 的算法上要复杂很多,带来的 CPU 的开销比 ORC 要略大
  • 在Spark场景下Parquet工作更好,Hive场景下ORC更好。Spark比Hive更有优势,Parquet可能是更好的选择

列存演进

数仓中的列存

默认情况下列按照 Column 拆分成单独的文件,也支持单个文件形式;支持更加丰富的索引;湖仓一体大趋势

存储侧下推- 更多的下推工作下沉到存储服务侧

更多下推工作下沉到存储服务侧;越接近数据,下推过滤的效率越高

Column Family 支持

Hudi 数据湖场景下,支持部分列的快速更新,把需要更新的列拆成独立的 Column Family,Update 操作实际效果有 10+ 倍的提升

image.png