数据库行存储与列存储,哪种更适合查询?
摘要:数据库列存储和行存储的区别 什么是列存储(Column-oriented Storage)? 在传统的数据库中,数据是一行一行写入和读取的。而列存储(Columnar Storage)顾名思义,是将数据表中的每一列数据单独集中存储在物理磁盘
数据库列存储和行存储的区别
什么是列存储(Column-oriented Storage)?
在传统的数据库中,数据是一行一行写入和读取的。而列存储(Columnar Storage)顾名思义,是将数据表中的每一列数据单独集中存储在物理磁盘上。
这意味着,表中同一列的所有数值会被连续地存放在一起。比如一个包含“姓名、年龄、职业”的表,在列存储中,“所有的姓名”存在一个数据块,“所有的年龄”存在另一个数据块。
什么是行存储(Row-oriented Storage)?
为了更好地理解列存储,我们需要对比传统的行存储。行存储是将一条记录(Row)的所有字段(Columns)连续存储在一起。当你写入一条新数据时,它的所有信息是作为一个整体被写入磁盘的。
💡 生活化的比喻:
行存储: 就像是一本个人档案册。每一页是一个人的所有信息(姓名、年龄、薪水)。如果你想查某一个人的全部信息,翻到那一页就能全看完;但如果你想算出所有人的“平均薪水”,你就必须把每一页都翻一遍。
列存储: 就像是分类账本。第一本全写名字,第二本全写年龄,第三本全写薪水。如果你想算“平均薪水”,只需要拿过第三本账本,里面全都是数字,一眼就能加起来,完全不需要理会名字和年龄。
行存储 vs 列存储:核心区别
这两种存储方式没有绝对的优劣,只有“是否适合特定的业务场景”。以下是它们的详细对比:
特性
行存储 (Row Storage)
列存储 (Column Storage)
数据物理分布
按行连续存储在一块
按列单独连续存储
适用核心场景
OLTP (联机事务处理),如电商交易、用户注册
OLAP (联机分析处理),如数据报表、商业智能分析
查询优势
极快地获取一条记录的所有字段
极快地对某几列进行聚合计算(如 SUM, COUNT, AVG)
I/O 效率
如果只查某一列,仍需将整行数据读入内存,产生大量无效 I/O
只读取需要的列数据,极大减少磁盘 I/O
数据压缩率
较低。因为一行中包含字符串、数字、日期等不同类型的数据,难以高效压缩。
极高。因为同一列的数据类型完全一致(例如全是数字),可以使用游程编码等高级压缩算法,通常能压缩到原来的 1/10。
增删改性能 (Insert/Update)
非常快。直接在末尾追加或定位修改即可。
较慢。插入一条记录需要拆分到不同的列文件中,通常采用“批量写入”策略来优化。
代表性技术/数据库
MySQL, PostgreSQL, Oracle, SQL Server
ClickHouse, HBase, Snowflake, Parquet (文件格式)
什么时候该用哪一个?
选择行存储: 如果你的系统是用来处理日常业务的(比如淘宝的购物车、银行的转账),操作特点是高频地插入、修改单条记录,并且每次查询都需要用到这条记录的大部分信息,那么行存储是你的不二之选。
选择列存储: 如果你的系统是用来做数据分析的(比如分析过去一年淘宝某个品类的总销售额、用户的平均年龄),操作特点是海量数据查询、很少修改数据、通常只关注表中的某几列进行统计,那么列存储能让你的查询速度提升成百上千倍。
行存储 vs 列存储 磁盘存储区别
数据在磁盘上的物理连续性,直接决定了底层操作系统读取数据时的 I/O (输入/输出) 消耗,这也是两者性能差异的根本来源。
为了最直观地说明,我们先假设有一张非常简单的“员工表”(Employee),包含三行数据和四个字段(列):
ID (编号)
Name (姓名)
Age (年龄)
Salary (薪资)
1
Alice
25
5000
2
Bob
30
6000
3
Carol
28
5500
磁盘的基本读取单位通常是“块(Block)”或“页(Page)”(比如 4KB 或 8KB)。我们来看看这三行数据是如何被塞进这些数据块里的。
1. 行存储的磁盘结构:打包放入
在行存储(如 MySQL 的 InnoDB 引擎)中,一条记录的所有字节是紧密挨在一起的。
磁盘上的物理排列大概是这样的:
[块 1]: 1, Alice, 25, 5000, 2, Bob, 30, 6000, 3, Carol, 28, 5500 ...
写入逻辑: 当新员工 Dave 入职时,数据库直接在这个文件的末尾(或者找一个有空隙的数据块)追加 4, Dave, 35, 7000。这被称为顺序写,速度非常快。
读取灾难(针对分析场景): 假设老板问:“公司的平均薪资是多少?”
数据库必须把包含这三行数据的整个数据块从磁盘读到内存中。
