⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 my.oschina.net/gaussdb/blog/5544252 「Gauss松鼠会」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

好多人最开始学习数据库的时候,是关系数据库,数据以表格形式存储,一行表示一条记录。其实这种就是典型的行存储(Row-based store),将表按行存储到磁盘分区上。

而一些数据库还支持列存储(Column-based store),它将表按列存储到磁盘分区上。

存储方式比较

这两者的差异如下图:

从图上可以看出,行存的时候,一行记录的属性值存储在临近的空间,然后接着是下一条记录的属性值。

而列存的时候,单个属性所有的值存储在临近的的空间,即一列的所有数据连续存储的,每个属性有不同的空间。

这里,大家可以自行思考一下这两种那种更适合查询,那种更适合修改?

在数据写入上的对比:

1)行存储的写入是一次完成。写入建立在操作系统的文件系统上,可以保证写入过程的成功或者失败,数据的完整性因此可以确定。

2)列存储由于需要把一行记录拆分成单列保存,写入次数明显比行存储多,再加上磁头需要在盘片上移动和定位花费的时间,实际时间消耗会更大。所以,行存储在写入上占有很大的优势。

3)还有数据修改,这实际也是一次写入过程。所以,数据修改也是以行存储占优。

在数据读取上的对比:

1)行存储通常将一行数据完全取出,如果只需要其中几列数据的情况,就会存在冗余列,出于缩短处理时间的考量,消除冗余列的过程通常是在内存中进行的。

2)列存储每次读取的数据是集合的一段或者全部,不存在冗余性问题,查找内容连续存储,特别适合投影。

3) 两种存储的数据分布。由于列存储的每一列数据类型是同质的,不存在二义性问题。比如说某列数据类型为整型 (int),那么它的数据集合一定是整型数据。这种情况使数据解析变得十分容易。相比之下,行存储则要复杂得多,因为在一行记录中保存了多种类型的数据,数据解析需要在多种数据类型之间频繁转换,这个操作很消耗 CPU,增加了解析的时间。所以,列存储的解析过程更有利于分析大数据。

4)从数据的压缩以及更性能的读取来对比。同一列的数据,数据类型一致,列存的模式下就适合数据压缩,不同的列可以采用不同的压缩算法,压缩存储就会带来 IO 性能的提升。

优缺点比较

表的存储类型是表定义设计的第一步,客户业务类型是决定表的存储类型的主要因素。行、列存储模型各有优劣,建议根据实际情况选择。

行、列存优缺点及适用场景比较见下表:

行存 列存
优点 数据被保存在一起。INSERT/UPDATE 容易。 查询时只有涉及到的列会被读取。投影 (Projection) 很高效。任何列都能作为索引。
缺点 选择 (Selection) 时即使只涉及某几列,所有数据也都会被读取。 选择完成时,被选择的列要重新组装。INSERT/UPDATE 比较麻烦。点查询不适合。
适用场景 点查询 (返回记录少,基于索引的简单查询)。增、删、改操作较多的场景。 统计分析类查询 (OLAP,比如数据仓库业务,此类型的表上会做大量的汇聚计算,且涉及的列操作较少,关联、分组操作较多)。即时查询(查询条件不确定,行存表扫描难以使用索引)。

行存与列存实验

openGauss 支持行列混合存储,可以在建表的时候指定存储方式。下面我们进行一下实验。

实验环境:华为云服务器 + openGauss 企业版 3.0.0 + openEuler20.03 创建行存表 custom1 和列存表 custom2 ,插入 50 万条记录。

openGauss=# create table custom1 (id integer,name varchar2(20)); 
CREATE TABLE
openGauss=# create table custom2 (id integer,name varchar2(20)) with (orientation = column);
CREATE TABLE
openGauss=# insert into custom1 select n,'testtt'||n from generate_series(1,500000) n;
INSERT 0 500000
openGauss=# insert into custom2 select * from custom1;
INSERT 0 500000

我们看下两个表的存储空间,比较 Size 列,可以看出列存表比行存表占用存储空间小的非常多,差不多是行存表空间的 1/7。

openGauss=# \d+ 
List of relations
Schema | Name | Type | Owner | Size | Storage | Description
--------+------------+-------+-------+------------+--------------------------------------+-------------
public | custom1 | table | omm | 24 MB | {orientation=row,compression=no} |
public | custom2 | table | omm | 3104 kB | {orientation=column,compression=low} |

比较下插入一条新记录的时间,列存表要稍微慢一点。

openGauss=# explain analyze insert into custom1 values(1,'zhang3'); 
QUERY PLAN
-----------------------------------------------------------------------------------------------
[Bypass]
Insert on custom1 (cost=0.00..0.01 rows=1 width=0) (actual time=0.059..0.060 rows=1 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
Total runtime: 0.135 ms
(4 rows)

openGauss=# explain analyze insert into custom2 values(1,'zhang3');
QUERY PLAN
-----------------------------------------------------------------------------------------------
Insert on custom2 (cost=0.00..0.01 rows=1 width=0) (actual time=0.119..0.120 rows=1 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.002 rows=1 loops=1)
Total runtime: 0.207 ms
(3 rows)

最后删除测试表。

openGauss=# drop table custom1; 
DROP TABLE
openGauss=#drop table custom2;
DROP TABLE

感兴趣的同学可以自己测试更多的的场景,比如创建大宽表、update 表等场景测试下。

选择建议

  • 更新频繁程度:数据如果频繁更新,选择行存表。
  • 插入频繁程度:频繁的少量插入,选择行存表。一次插入大批量数据,选择列存表。
  • 表的列数:一般情况下,如果表的字段比较多即列数多(大宽表),查询中涉及到的列不多的情况下,适合列存储。如果表的字段个数比较少,查询大部分字段,那么选择行存储比较好。
  • 查询的列数:如果每次查询时,只涉及了表的少数(<50% 总列数)几个列,选择列存表。(不要问剩下的列干啥用,甲方说有用就是有用。)
  • 压缩率:列存表比行存表压缩率高。但高压缩率会消耗更多的 CPU 资源。

注意事项

列存由于特殊的存储方式,使用时约束比较多。比如,列存表不支持数组、不支持生成列、不支持创建全局临时表、不支持外键,支持的数据类型也会比行存要少。使用时需要查看对应的数据库文档。

文章目录
  1. 1. 存储方式比较
  2. 2. 优缺点比较
  3. 3. 选择建议
  4. 4. 注意事项