首页/数据/数据工程与 ETL 速查/列式存储与行式存储
管道基础52 条

列式存储与行式存储

行式存储适合按行读取与点查更新;列式存储把同列数据连续存放,分析型查询只读少量列时 IO 明显更省,且利于压缩与向量化计算。

两种存储布局的区别

行式存储把一行的所有列连续放在一起,读一行就要读一次连续段,因此点查与单行更新很快。列式存储把同一列的数据连续存放,分析型查询只读少数几列时,IO 量能按列裁剪,压缩率也更高——因为同一列数据类型相同、取值相近。两者不是谁替代谁,而是面向不同访问模式:事务系统多用行存,分析系统多用列存。

对比

维度行式存储列式存储
读取模式整行读取,点查友好按列读取,扫描少数列划算
压缩效率同行列类型混杂,压缩率一般同列同类型,压缩率高
写入模式追加与更新都方便批量写入友好,单行更新代价高
典型场景OLTP 事务、单行更新OLAP 分析、宽表扫描
代表实现MySQL InnoDB、PostgreSQL 堆表Parquet、ORC、ClickHouse 列存

基本信息

列存文件结构行组(row group)内按列分块,附统计信息
裁剪手段分区裁剪、行组统计跳过、列裁剪
编码优化字典编码、游程编码,对有序数据效果显著
向量化按列批量处理,配合现代 CPU 的批处理指令
选型要点先看访问模式:点查多还是扫描多

同一份数据的两种读法

同一份数据的两种读法
查询:SELECT SUM(amount) FROM orders WHERE dt='2026-10-11'
行式:读出该分区所有行的全部列,再丢弃用不到的列
列式:只读 amount 与 dt 两列的数据块,其余列完全不解码
结论:列式扫描数据量可能只有行式的十分之一

典型使用场景

  • 业务库选择行存:订单创建、单条更新、按主键查询
  • 数仓与湖上选择列存:大范围聚合、宽表扫描、指标计算
  • 混合负载:用行库承接事务,定期同步到列存供分析
  • 需要频繁 upsert 的湖表:依靠表格式的写入机制弥补列存更新代价
  • 读多写少的归档数据:列存压缩后长期保存成本更低
数据湖/数仓以列存为主,但需要频繁按行更新的场景仍需行存或支持 upsert 的表格式。
列存的压缩收益与「同列取值相近」高度相关:按时间分区并排序写入后,压缩率通常明显优于随机插入。

易错点

  • 列存单行更新代价高,别拿 Parquet 直接当业务库改数
  • 列存文件过小会使元数据占比过高,条带/行组粒度也要合理
  • 以为列存万能,遇到点查与高频更新场景性能反而更差
  • 写入不做排序与分区,同一列的值域跨度大,压缩与裁剪都失效
  • 只比文件大小不比扫描量,压缩率高但裁剪不生效时查询并不会更快

数据来源与参考

  • Apache Parquet 官方文档:Motivation
  • 《数据密集型应用系统设计》存储与检索章节
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌