数据库行存储与列存储,哪种更适合查询?

摘要:数据库列存储和行存储的区别 什么是列存储(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。这被称为顺序写,速度非常快。 读取灾难(针对分析场景): 假设老板问:“公司的平均薪资是多少?” 数据库必须把包含这三行数据的整个数据块从磁盘读到内存中。
阅读全文