行存与列存——数据表的存储方式
以下是一个简单的数据表:
id | name | age | salary |
---|
20220001 | Jack | 18 | 4500 |
20220002 | Bob | 20 | 6000 |
20220003 | Michael | 25 | 5300 |
20220004 | Michele | 22 | 4800 |
20220005 | Mike | 18 | 6500 |
采用按行存储,数据表在磁盘上的存储形式:
tuple1: | 20220001 | Jack | 18 | 4500 |
tuple3: | 20220003 | Michael | 25 | 5300 |
tuple4: | 20220004 | Michele | 22 | 4800 |
tuple5: | 20220005 | Mike | 18 | 6500 |
采用按列存储,数据表在磁盘上的存储形式:
tuple1: | 20220001 | 20220002 | 20220003 | 20220004 | 20220005 |
tuple2: | Jack | Bob | Michael | Michele | Mike |
tuple4: | 4500 | 6000 | 5300 | 4800 | 6500 |
可以看到,行存和列存的区别在于一个tuple内存储的是行数据还是列数据。对于按列存储,由于每一列的数据相似度较高,对数据进行压缩时压缩比会很大。对于不同的应用场景,这两种存储方式各有优缺点。
场景一:对id进行等值查找并显示整条记录:select * from table where id = ???;
如采用按行存储,只需要通过索引或者直接找到id符合条件的行,然后读取该行的tuple即可。如采用按列存储,由于需要获取到每一个字段的值,在查找到id符合条件的行号后,需要读取剩下的每一个tuple,以获取相应字段的值。这种场景下,显然按行存储性能占优。
场景二:计算某一个字段的和或平均值:select AVG(salary) from table;
如采用按行存储,需要读取表中的所有tuple,获取每一个tuple的salary字段,然后进行求平均值。如采用按列存储,则只需要读取存储salary的一个tuple,即可求平均值。这种场景下,显然按列存储性能占优。
场景三:插入、修改、删除某条记录。如采用按行存储,只需要插入或删除一个tuple即可。如采用按列存储,则需要对每一个tuple进行修改。显然按行存储性能占优。
综上,对于OLTP交易类业务,一般复杂计算较少而存取较多,要求读写时延小,按行存储优势较大。对于OLAP分析类业务,一般有大量的聚合、连接、统计等计算操作,和仅仅涉及到一个宽表中个别列的复杂查询,而数据修改、随机查询等操作较少,按列存储优势较大。