存储模型

行存储与列存储

传统的关系数据库如 Oracle、DB2、Mysql 等都是将数据以行记录为单位进行组织,所以数据读写操作需要遍历行记录中所有的列,在存储机制上,行存储将行记录中各列的数据值串在一起进行存储,并且先存完第一行再存第二行。而列存储是一种区别于传统行存储的新型读写模式,列存储以列数据集合为单位进行存储,是把一列中的数据值串在一起进行存储,先存完第一列,再存第二列。

image.png

行存储,顾名思义即是将数据是按行存储,行存储的写入是一次性完成,消耗的时间比列存储少,并且能够保证数据的完整性;其插入与更新操作更为容易。但是其缺陷在于建立索引需要花费大量时间和资源,没有索引的话查询会产生大量的 IO,导致效率低下;并且数据库必须被大量膨胀才能满足性能的需求。

列存储,数据按列存储,每一列单独存放,数据即是索引。只查询涉及的列,会大量降低系统 IO,适合并发查询;数据类型一致,数据特征相似,能对数据进行高效压缩,并且非常适合做聚合操作。不过列存储缺乏数据完整性保证,写入效率低,因此不适合频繁的删除与更新操作。

行式存储

列式存储

优点

数据被保存在一起,INSERT/UPDATE 容易

查询时只有涉及到的列会被读取,投影(Projection)很高效,任何列都能作为索引

缺点

选择(Selection)时即使只涉及某几列,所有数据也都会被读取

选择完成时,被选择的列要重新组装,INSERT/UPDATE 比较麻烦

场景

适合数据存储写入、更新较多的场景,比如 OLTP。当数据量很大时,查询性能远不及列存储

不适合数据频繁写入、更新的场景,主要适合频繁查询的场景,大数据环境下优势更明显,比如分布式实时查询

从写方面来看,行存储的写入是一次完成,也就是说行存储各字段写入是在一次 IO 中完成,而列存储由于需要把一行记录拆分成单列保存,写入次数明显比行存储多,也就是说要多次 IO 才能完成,而字段越多,IO 次数越多,所以在写入上行存储具有明显的优势。再从读方面来看,行存储通常将一行数据完全读出,如果只需要其中几列数据的情况,就会存在冗余列,出于缩短处理时间的考量,消除冗余列的过程通常是在内存中进行的,而列存储读取则只需要读取关心的几个列数据,明显减少了读取的数据量,如果行记录字段越多性能优势就越明显。

另外由于列存储的每一列数据类型是同质的,不存在二义性问题,比如说某列数据类型为整型(int),那么它的数据集合一定是整型数据。这种情况使数据解析变得十分容易,而且因为存储单元的数据结构一致,可以很容易利用差值编码等压缩方法来进行压缩存储而且压缩比可以非常高。相比之下,行存储则要复杂得多,因为在一行记录中保存了多种类型的数据,数据存储不容易压缩,数据解析需要在多种数据类型之间频繁转换,这个操作很消耗 CPU,增加了解析的时间。另外列存储相对行存储更为灵活,逻辑上一行数据可以按列将数据存放到不同的地方,也可以是不同机器上,这样可以在执行查询分析任务时可以按机器节点并行进行查询计算,而行存储不容易进行并行查询,需要一定中间件的支持。

这里以 Spark MaxCompute 为例,阐述列存储模式的压缩与检索技巧,经过字典表进行数据压缩后,表中的字符串才都变成数字了。正因为每个字符串在字典表里只出现一次了,所以达到了压缩的目的:

image

在查询过程中,查询引擎仅去字典表里找到字符串对应数字(只进行一次字符串比较),然后用数字去列表里匹配,匹配上的位置设为 1;把不同列的匹配结果进行位运算得到符合所有条件的记录下标,使用这个下标组装出最终的结果集。

image

Wide Column | 宽表

BigTable 及其他类似的数据库也提出了所谓宽表(Wide Column)模型的概念,目前很多半结构化或者结构化的数据都是基于该模型。这里以阿里云的表存储为例:

image.png

关系型数据库中往往是二维模型,并且包含了固定的 Schema;而上述宽表模型而包含了三个维度,除了标准的行、列之外,其还可以根据时间维度来存放数据,即根据不同的时间戳来保存不同的版本。

  • Primary Key & Partition Key: 每行都有一个主键,由多个(1-4)列组成。 主键使用固定模式定义,主要用于唯一标识一行数据。 主键的第一列称为分区键,用于对表进行分区。 每个分区都分配给不同的机器进行维护。 在同一分区键中,提供了跨行事务。

  • Attribute column: 除行中的主键列之外的所有列都是属性列。 属性列对应于多个值,不同的值对应于不同的版本,行可以存储无限数量的属性列。

我们还可以针对 Attribute Column 中的值定义不同的属性:

  • 生存时间:可以为每个表定义生存时间。 例如,如果将生存时间配置为一个月,则将自动清除在一个月之前写入表数据的数据。 数据的写入时间由版本确定,版本通常由数据写入服务器端的服务器时间确定,也可以由应用程序指定。

  • 最大版本号:可以为每个表定义每列中保存的最大版本数,用于控制列中的版本数;系统会自动清除超过最大版本数的数据。

Time Series Model | 时间序列模型

时间序列模型是我们为消息数据场景创建的新数据模型。 它可以满足消息数据场景的特殊要求,保留消息顺序,海量消息存储和实时同步。

  • Time series ID: 唯一标识时间序列。

  • Time series Meta: 时间序列元数据,可以包含任何键值对属性。

  • Message Sequence: 它包含时间序列中的所有消息。 消息按顺序存储,并根据写入顺序分配增量 ID。 消息序列可以携带无限数量的消息。 可以随机使用消息 ID 来定位序列内的消息,并且可以提供按升序或降序扫描。

  • Message Entry: 它包含消息的详细内容,可以包含任何键值对。