为什么列式存储更适合OLAP?

列式存储是一种数据存储方式,其核心思想是将数据按列而非按行进行组织和存储。它与传统的行式存储在数据布局、适用场景和性能特征上有显著差异。

Clickhouse等OLAP数据存储系统正是由于其使用列式存储,很大程度的提高了数据查询和分析能力,这篇文章我就向大家分享一下行式存储和列式存储到底有何区别?为什么Clickhouse等OLAP系统更偏向使用列式存储?

先说一下基本概念

行式存储列式存储 是两种不同的数据存储方式。注意是底层的存储方式不同,对于我们上层使用而言都是差不多的表结构。

行式存储 将每一行的数据连续存储在一起,适合事务处理,可以快速读取整条记录;而列式存储将每一列的数据连续存储在一起,适合数据分析,查询特定列时只需读取该列数据,压缩效率更高。

简单来说,行式存储适合频繁的增删改查操作,列式存储则更适合大数据分析和聚合查询。

举例

行式存储(Row-Based),按行连续存储:

javascript 复制代码
| 用户ID | 姓名  | 年龄 | 地址 |
| ------ | ----- | ---- | ---- |
| 1      | Alice | 25   | 北京 |
| 2      | Bob   | 30   | 上海 |
| 3      | Carol | 28   | 深圳 |

磁盘存储结构(假设每行连续存放):

javascript 复制代码
1,Alice,25,北京 | 2,Bob,30,上海 | 3,Carol,28,深圳

列式存储(Column-Based),列式存储示例(按列独立存储):

javascript 复制代码
用户ID列 → [1, 2, 3]
姓名列   → [Alice, Bob, Carol]
年龄列   → [25, 30, 28]
地址列   → [北京, 上海, 深圳]

磁盘存储结构(每列独立存储为文件):

javascript 复制代码
用户ID.bin → 1,2,3
姓名.bin → Alice,Bob,Carol
年龄.bin → 25,30,28
地址.bin → 北京,上海,深圳

画个图可能更清楚一些:

列式存储与行式存储的核心差异

1)数据组织方式

行式存储 :数据按行连续存储。例如,表中一行数据的所有字段(如 用户ID、姓名、年龄、地址)在磁盘上连续存放,形成一个数据块。适用场景:事务型处理(OLTP),如频繁的单行读写、点查询。

列式存储 :数据按列连续存储。例如,所有用户的 用户ID 存储在一起,所有 年龄 存储在一起,形成多个独立的列数据块。适用场景:分析型处理(OLAP),如聚合统计、批量扫描。

2)I/O效率

行式存储 :读取单行数据时效率高,但若需统计某列的聚合值(如 SUM(年龄)),需要读取整行数据(包含无关字段),导致 I/O放大

列式存储 :仅读取目标列的数据,显著 减少I/O量 。例如统计 年龄总和 时,只需读取 年龄 这一列。

举例

行式存储的I/O过程:

javascript 复制代码
需要读取所有行的完整数据(包括无关字段):
1,Alice,25,北京 → 提取25
2,Bob,30,上海   → 提取30
3,Carol,28,深圳 → 提取28

总读取数据量为3行 × 4列 = 12个字段,有效数据占比为25%

列式存储的I/O过程:

javascript 复制代码
仅读取年龄列文件(年龄.bin → [25, 30, 28]):
直接获取所有年龄值,无需处理其他字段。

总读取数据量为3行 × 1列 = 3个字段,有效数据占比为100%

3)数据压缩

行式存储:单行内不同列的数据类型差异大(如字符串、数值混杂),压缩率低。

列式存储 :单列数据具有相同类型和语义,可通过 高效压缩算法(如LZ4、ZSTD、Delta编码)大幅降低存储空间(通常压缩比可达5-10倍),同时减少磁盘到内存的数据传输量。

4)CPU计算优化

针对列式存储而言,现代CPU支持单指令多数据流(SIMD),可对连续的同类型列数据批量计算(如一次处理128个数值),显著提升聚合计算速度。其次,连续存储的列数据更易被CPU缓存命中,减少内存访问延迟。

ClickHouse为何选择列式存储?

ClickHouse专为OLAP场景设计,其核心需求是 高速处理海量数据的聚合查询,而列式存储的以下特性完美契合这一目标:

减少数据扫描量:OLAP查询通常仅涉及少数列(如统计某几列的SUM/AVG)。列式存储仅需读取相关列,避免加载无关数据。

最大化压缩效率:高压缩率不仅节省存储成本,还减少磁盘到内存的数据传输时间,提升查询吞吐量。

向量化执行引擎:ClickHouse的查询引擎针对列式数据设计,可批量处理列数据,利用SIMD指令加速计算。

预聚合与索引优化 :列式存储便于实现稀疏索引、跳数索引(如GRANULARITY),快速定位数据块,减少扫描范围。

场景对比

操作 行式存储 列式存储
单行读写(如INSERT) 快(顺序写) 慢(需更新多列文件)
全表扫描(如COUNT) 快(仅读一列)
聚合查询(如SUM) 慢(读所有行) 快(仅读一列)
压缩率

小总结

列式存储通过按列组织数据、减少I/O、高效压缩和向量化计算,在OLAP场景中实现了比行式存储高1-2个数量级的查询性能。ClickHouse等OLAP系统正是基于这些原理,选择列式存储作为其高性能分析引擎的核心基础,使其在海量数据实时分析领域表现出色。

相关推荐
_一条咸鱼_4 分钟前
大厂AI大模型面试:涌现原理
人工智能·深度学习·面试
peiwang24520 分钟前
网页制作中的MVC和MVT
后端·mvc
酱酱们的每日掘金26 分钟前
一键连接 6000 + 应用dify MCP 插件指南、谷歌 AI 编程产品一网打尽、MCP玩出花了丨AI Coding 周刊第 4 期
前端·后端·ai编程·mcp
橘子青衫44 分钟前
多线程编程探索:阻塞队列与生产者-消费者模型的应用
java·后端·架构
胡萝卜糊了Ohh1 小时前
scala
开发语言·后端·scala
Java致死1 小时前
SpringBoot(一)
java·spring boot·后端
草捏子1 小时前
别让外部接口"毒死"你的系统!防腐层技术一定要知道
后端
uhakadotcom1 小时前
🚀 使用 Bun 快速搭建 HTTP 服务器:一步步教程
前端·javascript·面试
进击的阿晨1 小时前
🔥想自学 Java 却踩坑无数?从月薪 3K 到 15K 程序员的逆袭笔记来啦!
java·后端·面试
TS古宁2 小时前
CST1017.基于Spring Boot+Vue共享单车管理系统
java·前端·vue.js·spring boot·后端