我们来深入探讨列式存储(以 Parquet 为代表)的优劣势。这将帮助我们更清晰地理解它为何在特定场景下表现卓越,又在哪些场景下可能不适用。
列式存储的核心优势
这些优势主要围绕性能、存储效率和分析友好性。
-
极高的查询性能(针对分析型查询)
- 列裁剪: 这是最大的优势。当查询只涉及少数几列时,数据库或计算引擎只需从磁盘上读取这些列的数据,而跳过其他所有列。这极大地减少了 I/O 操作,这是大数据处理中最主要的瓶颈。
- 示例: 在一个包含 100 列的用户表中,查询“统计不同城市的用户数”只需要读取
city_id这一列,而不是全部 100 列。I/O 量可能减少 99%。
-
卓越的压缩效率
- 数据类型一致: 同一列中的数据具有相同的数据类型(例如全是整数、字符串或布尔值),这使得可以应用针对该类型高度优化的编码和压缩算法。
- 数据模式相似: 同一列中的值通常非常相似(例如
country列中会有大量重复的“中国”、“美国”),这为字典编码、游程编码等提供了绝佳机会,能获得极高的压缩比。 - 好处: 更小的文件尺寸意味着更低的存储成本和更快的网络传输(在分布式系统中尤为重要)。
-
强大的向量化执行与谓词下推
- 向量化处理: 由于数据按列连续存储,CPU 可以高效地将一整列数据加载到缓存中,并对连续的内存块执行相同的操作(例如,对一亿个整数进行求和)。这大大减少了函数调用开销,更好地利用了现代 CPU 的流水线和 SIMD 指令。
- 谓词下推: 列存格式(如 Parquet/ORC)会在元数据中存储每个数据块的统计信息(如最小值、最大值)。查询时,引擎可以先检查这些统计信息,直接跳过不满足条件的整个数据块。
- 示例: 查询
WHERE date > ‘2024-01-01’,引擎会检查每个数据块的date列最大值,如果其最大值是2023-12-31,那么这个数据块就会被完全跳过。
-
更适合于现代 CPU 和存储架构
- 列处理模式更符合顺序读取,能更好地利用高速缓存,减少 CPU 缓存未命中。
列式存储的核心劣势
这些劣势主要围绕数据修改、查询类型和开销。
-
点查询和事务操作性能差
- “行”的组装成本高: 如果需要选择或更新一条完整的记录(例如
SELECT * FROM users WHERE user_id = 123),引擎必须从所有不同的列文件中定位并读取该行的各个片段,然后将其重新组装成一行。这个“组装”过程非常昂贵,I/O 是随机的,性能远低于行式存储。 - 不适合 OLTP: 对于需要频繁插入、更新、删除单条记录的场景(如电商交易、银行转账),列存是错误的选择。
- “行”的组装成本高: 如果需要选择或更新一条完整的记录(例如
-
数据加载与写入速度较慢
- 写入放大: 写入一条新记录时,需要将其拆解,并追加到每个对应列文件的末尾。这涉及到更多的文件系统操作,比简单地将整行追加到一个文件末尾要慢。
- 不适合流式写入: 列存格式通常为批量加载优化,不适合高频率、小批量的实时写入。
-
不适合全表扫描或返回大量行的查询
- 如果查询确实需要访问大部分列和大部分行(即
SELECT *且无过滤),列存的优势就变成了劣势。因为从多个列文件中随机读取和组装行的开销会超过列裁剪带来的好处。
- 如果查询确实需要访问大部分列和大部分行(即
-
存储元数据开销
- 列存文件需要维护丰富的元数据(如 Schema、统计信息、索引等),对于非常小的数据集,这些元数据的开销可能比数据本身还大,显得“杀鸡用牛刀”。
总结与对比
| 特性 | 列式存储 | 行式存储 |
|---|---|---|
| 最佳适用场景 | OLAP: 数据仓库、大数据分析、报表生成、即席查询。 | OLTP: 业务交易系统、客户关系管理、内容管理系统。 |
| 典型查询 | SELECT few_columns, COUNT(), SUM(), WHERE | SELECT *, INSERT, UPDATE, DELETE |
| I/O 效率 | 高(当只查询部分列时) | 高(当需要整行数据时) |
| 压缩效率 | 极高 | 一般 |
| 数据写入速度 | 慢 | 快 |
| 点查询性能 | 差 | 优 |
| 模式灵活性 | Schema 通常需要预定义且严格 | 更灵活,更容易处理可变字段 |
如何选择?
-
选择列式存储(Parquet/ORC)当:
- 你的工作负载是分析型的,涉及大量数据的扫描、聚合和过滤。
- 查询通常只访问表的一部分列。
- 数据主要是批量加载,而非频繁的单条写入/更新。
- 你的目标是降低存储成本并提升查询速度。
-
选择行式存储(CSV/JSON/Avro)当:
- 你的工作负载是事务型的,需要频繁的按主键读取整行、插入或更新。
- 你的查询通常是
SELECT *或需要返回完整的记录。 - 你需要流式写入或低延迟写入。
在现代数据架构中,一种常见的模式是:使用行式数据库(如 MySQL, PostgreSQL)处理前端事务(OLTP),然后通过 ETL 过程将数据同步到列式存储(如 Parquet 文件存储在数据湖中),最后使用 Spark、Presto 等引擎进行分析(OLAP)。这充分发挥了两种存储格式各自的优势。
的优劣势&spm=1001.2101.3001.5002&articleId=154077673&d=1&t=3&u=9a5c187a1499466a8dd9e75e63c6fe6a)

被折叠的 条评论
为什么被折叠?



