面向列的存储格式: ORC 和 Parquet

面向列的存储格式: ORC 和 Parquet

突然发现,原计划的双周更已经被莫名奇妙地推迟了整整一周,果然还是有点上强度啊。

想想……该写个关于什么的文章呢……因为最近读了前 Google 大佬 Jordan Tigani 的几篇博客,提到了几次 DuckDB,这个在这之前其实也大概了解过,虽然大佬的文章有些称赞它的地方,再次引起了我对它的兴趣,比如:

The DuckDB website used to have a disclaimer that said, “Please don’t complain about performance, we’re trying to focus on correctness before we try to make it fast.” Not all databases apply the same approach. You can make a car faster by removing safety gear like airbags, traction control, crumple zones, emissions controls, etc. But most people don’t want to drive a car like that. Databases are no different; you can make them faster if you remove overflow checks, don’t flush writes, give approximate results to certain operations, or don’t provide ACID guarantees. Some of the systems that do well on these benchmarks apply these kinds of short-cuts, but I wouldn’t want to use them except in controlled circumstances.

但毕竟我没有太多关于 DuckDB 的使用心得,本着不乱带路的原则,就仅仅作为一个插曲写进来吧。总的来说,DuckDB 是:

  • 一个轻量级的数据库
  • 可以支持不同的使用场景,OLTP、OLAP(小规模的)
  • 以及提供了你意想不到的、更便利的 SQL 语法
  • 以及有不同语言的连接器

对此感兴趣的朋友,可以去 DuckDB 的官网逛一逛,以及 Even Friendlier SQL with DuckDB 这篇文章会有一些感性的认识。

插曲之后,回到正题。近几篇文章都跟大数据技术相关,近几周翻看过的与这相关的,就定了这个话题:面向列的存储,ORCParquet

话说,这两个其实是很大的话题,想在博客上做技术讲解那很显然是不现实的。所以,除了一点点关于它们俩的基本介绍,我只想写一些我自己觉得有意思的发现。更详细的原理、实践、性能优化之类的,建议走官方文档或者自行 AI 都是推荐的方式。

ORC 和 Parquet 的简要介绍

提示:以下内容为 AI 生成。

ORC(Optimized Row Columnar)和Parquet是两种广泛使用的列式存储文件格式,适用于大数据处理和分析。以下是对它们的比较:

1. 概述

  • ORC:由Hortonworks开发,最初为Apache Hive设计,优化了列式存储和查询性能,广泛用于Hadoop生态系统。
  • Parquet:由Apache软件基金会开发,起源于Twitter和Cloudera,设计目标是高效处理复杂数据,适用于多种大数据框架(如Spark、Hive、Impala等)。

2. 存储结构

  • ORC
    • 数据按列存储,分成多个Stripes(数据块),每个Stripe包含索引、数据和统计信息(如最小值、最大值、计数)。
    • 支持轻量级索引(Row Group Index),便于快速跳跃式扫描。
    • 提供Bloom Filter和统计信息,优化查询性能。
  • Parquet
    • 同样按列存储,数据分为Row Groups,每个Row Group包含列块(Column Chunks)和元数据。
    • 元数据存储在文件末尾,支持高效的列裁剪和谓词下推。
    • 支持更复杂的数据结构,如嵌套数据(通过Dremel模型)。

为什么需要列存结构?

常规来讲,

对于 OLTP 系统,它们在读取的时候,是小量的随机读,且都是以数据行的形式,因为我们需要获取比如一篇文章、一条Blog的所有信息,然后在前端取现实。从 SQL 的视角,就是:

1
2
3
4
SELECT
*
FROM blogs
WHERE creator = <user_id>;

而对于 OLAP 系统,是大量的连续读取,且以分析型 SQL 为主,每次仅需要读取很少的列,比如我们要按城市的维度统计最近一个月的用户活跃数。从 SQL 的视角,就是:

1
2
3
4
5
6
7
SELECT
city,
COUNT(distinct user_id) AS cnt
FROM
login_history
WHERE create_date between 最近一个月
GROUP BY city;

两者最大的区别就在于一次访问的列数不同,简单来说,列存就是为了减少在分析场景下加载少量数据列的压力的。

有意思的发现:ORC 和 Parquet 都是 Apache 的, 那是否 后出生的 完爆了 生得早的?

答案是:并不是。

从时间上,Parquet 和 ORC 都出生于 2013 年,Parquet 仅仅晚几个月。

它们俩有各自适用的场景,

  • ORC 依然是 Hadoop 生态,Hive 圈的常客,当然 Spark 在内
  • 而 Parquet 胜在生态系统支持的更多,除了 Hadoop, 还有比如 Spark、Trino、Cloud S3

对于我来说,如果项目本身有潜在的更多的外部生态要融入,那么我会选择 Parquet。

最后

ORC 和 Parquet 固然还有其他的差异点,比方说支持的数据类型差异、性能差异等。那些不是说不重要,只是正在我看来不那么重要,毕竟在开发界有个病症叫 Premature Optimization。

不过,关于性能,也说一下自己曾经的拙劣经验。曾几何时,我读到过说 Parquet 比 ORC 更快的文章。接着,我随便写了一些并不权威的、简陋的测试代码,针对分别以 ORC 和 Parquet 创建的数据表做了一丢丢测试,得到的结果是 Parquet 并没有比 ORC 读取更快。非常粗糙的测试,对吧?有些年头了,当时用的 SQL 、测试数据长相、服务器配置等等,一概没有。

但是,我想说的是,性能很大程度上取决于项目的数据使用特征,而这个是非常主观的(因为大部分时候的评测文章不太可能把所有的环境因素都写进去),别人的基准测试对你的项目来说,兴许根本就没有任何参考意义。

最后的最后

欢迎读者在留言区分享你们觉得有意思的东西给我,我会根据自己的时间来写一写各位推荐的技术,当然,得在我啃得动的前提下。