行存和列存

行存和列存-大数据存取的选择

行存和列存.assets/20220520202519.png 目前大数据存储有两种方案可供选择:行存储(Row-Based)和列存储(Column-Based)。

定义

我们常用的关系型数据库mysql,oracle等都是基于行存储,以最常用的mysql数据库innodb引擎为例。多个连续的行记录,组成一个data page(大小16k),然后按照B+树的结构进行组织存储。
%E8%A1%8C%E5%AD%98%E5%92%8C%E5%88%97%E5%AD%98.assets/20220520202548.png
%E8%A1%8C%E5%AD%98%E5%92%8C%E5%88%97%E5%AD%98.assets/20220520202618.png

列式存储(column-based)是相对于传统关系型数据库的行式存储(Row-basedstorage)来说的。简单来说两者的区别就是如何组织表:

  • Row-based storage storesatable in a sequence of rows.
  • Column-based storage storesatable in a sequence of columns.
%E8%A1%8C%E5%AD%98%E5%92%8C%E5%88%97%E5%AD%98.assets/20220520202658.png

行存 Vs 列存

写入

  • 行存储的写入是一次完成。如果这种写入建立在操作系统的文件系统上,可以保证写入过程的成功或者失败,数据的完整性因此可以确定。
  • 列存储由于需要把一行记录拆分成单列保存,写入次数明显比行存储多,再加上磁头需要在盘片上移动和定位花费的时间,实际时间消耗会更大。所以,行存储在写入上占有很大的优势。
  • 还有数据修改,这实际也是一次写入过程。不同的是,数据修改是对磁盘上的记录做删除标记。行存储是在指定位置写入一次,列存储是将磁盘定位到多个列上分别写入,这个过程仍是行存储的列数倍。所以,数据修改也是以行存储占优。

读取

  • 数据读取时,行存储通常将一行数据完全读出,如果只需要其中几列数据的情况,就会存在冗余列,出于缩短处理时间的考量,消除冗余列的过程通常是在内存中进行的。
  • 列存储每次读取的数据是集合的一段或者全部,如果读取多列时,就需要移动磁头,再次定位到下一列的位置继续读取。

解析

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

总结

对比方面 行存储 列存储
存储方式 按行存储 按列存储,即每一列单独存放
数据完整性 提供数据完整性保证 缺乏数据完整性保证
写性能 写入是一次完成,写入效率高 把一行记录拆分成单列保存,写入次数明显比行存储多,写入效率低
读性能 读取少数几列时,需遍历其他无关列,IO开销较大;读取整行数据时,依次顺序读即可,性能高 读取少数几列时,无需读取无关列,性能高;读取整行时,需分别读取所有列,并拼装成行,性能低
索引 没有索引的查询使用大量I/O。比如一般的数据库表都会建立索引,通过索引加快查询效率 数据即索引
数据压缩 每行数据存储在一起,压缩比较低 以列为单位存储数据,这使得类型相同的数据存放在一起,对压缩算法友好,压缩比较高
典型代表 Text File、 Sequence File等 ORC、 Parquet、 Carbon Data等
应用领域 商业领域/互联网 互联网
  • 如果首要考虑是数据的完整性和可靠性,那么行存储是不二选择,列存储只有在增加磁盘并改进软件设计后才能接近这样的目标。
  • 如果以保存数据为主,行存储的写入性能比列存储高很多。
  • 在需要频繁读取单列集合数据的应用中,列存储是最合适的。
  • 如果每次读取多列,两个方案可酌情选择:
    • 采用行存储时,设计中应考虑减少或避免冗余列;
    • 若采用列存储方案,为保证读写入效率,每列数据尽可能分别保存到不同的磁盘上,多个线程并行读写各自的数据,这样避免了磁盘竞用的同时也提高了处理效率。
  • 无论选择哪种方案,将同内容数据聚凑在一起都是必须的,这是减少磁头在磁盘上的移动,提高数据读取时间的有效办法。

适用场景

  • 行存储的写入是一次性完成,消耗的时间比列存储少,并且能够保证数据的完整性,缺点是数据读取过程中会产生冗余数据,如果只有少量数据,此影响可以忽略;数量大可能会影响到数据的处理效率。
    • 所以,行存对于 OLTP 比较友好,一行记录的所有列连续存储,一次IO可以实现整行读取或者写入,实现数据库的ACID特性就比较简单。但在读取的时候会将整行数据全读出来,在一些分析场景下压力会有点大。
  • 列存储在写入效率、保证数据完整性上都不如行存储,它的优势是在读取过程,不会产生冗余数据,这对数据完整性要求不高的大数据处理领域,比如互联网,犹为重要。
    • 所以,列存则是对于 OLAP 非常友好,但在刷盘的时候压力可能会比较大,如果一个 table 有很多 column,写入性能可能会有点影响。

参考