全部产品
云市场

列式存储简介

更新时间:2019-08-23 14:48:46

列式存储简介

DRDS作为具有高度扩展性的OLTP型数据库产品,不仅稳定支持了阿里集团内的大量业务,而且作为在云产品,也赢得了众多具有扩展性诉求的客户的青睐。分析型只读实例是主实例的一种补充,可以用于辅助主实例进行一些“重负载”的操作。为了进一步丰富分析型只读实例的场景,今年DRDS团队又在基于行存技术的RDS只读实例的基础上,推出了基于列式存储技术的分析型只读实例,供用户选择。本文将以列存技术切入点,帮助用户选择合适的选型。

DRDS列式存储技术:
关系型数据库逻辑上的表现形式都是“行”。所谓“行存”和“列存”是指数据在物理存储上的组织方式。

  • “行”式的存储(尤其是以B-Tree及其衍生算法为核心的实现形式)在关系型数据库产品中占主导地位,尤其是OLTP型数据库领域。
  • “列”式的存储,作为关系型数据库中的另一类存储形式,则在分析型的场景中有着比较多的应用。

关于行存和列存的综述性的文章有很多,这里便不再赘述。

DRDS列式存储的技术,脱胎于一款长期服务于阿里集团内部的列式分析型数据库引擎产品。该产品作为高度兼容MySQL的分析型引擎,在日志分析,BI加速以及冷数据存储等多个场景里有着大量应用。去年随着阿里集团内部的组织升级,也被赋予了新的使命,即丰富DRDS使用场景,提供HTAP解决方案。

DRDS列式存储的基本结构如下。
image.png

所有数据总体以列为单位进行组织。同时,以65536行为单位(一下称行组)对列中的行进行压缩编码。本例中共有4列,3个行组,所以产生12个压缩数据块。在压缩编码的同时,对于每个压缩数据块,同时生成一系列数值统计信息,用于加速查询。除主键外,对于所有的列,默认没有额外的索引。

以下的例子可以用于说明统计信息在查询中的作用。
image.png
行组中数据的统计信息体量很小,通常在第一次访问后就常驻内存。当一条查询下发至引擎,统计信息首先被用于过滤数据。图例中,红色代表通过统计信息的判断,压缩块中数据完全不符合查询条件,绿色代表完全符合,黄色代表部分符合。对于完全不符合,或完全符合条件的数据块,可以完全不进行数据加载,因此可以节约大量磁盘IO。进而达到加速查询的效果。

下一张图,进一步说明,多种统计信息在过滤加速中的作用。
image.png
图中SQL对“Datetime”列进行过滤,假设datetime中数据分布如下,则通过查看统计信息中的min,max值,即可迅速过滤掉行组1,2。除此之外,存储引擎中可以保存Histogram和bloom filter,用于监测查询条件是否,落入min, max之间数值空洞之中的。

下图中描述的是压缩。
image.png
DRDS列式存储默认对所有列进行压缩。对于数值型,首先采取的是基础差值的压缩方式,可将原始数据,通过去掉最小值的方式,降低存储精度(例如从32为,降维为16位或8位)。之后再经过一轮通用压缩,最终存储为压缩块。解压缩的方式正好是压缩的逆向。对于字符类型,数据压缩通常通过通用压缩算法实现。数据的压缩表现与数据分布的特点有比较大点相关性。在TPC-H数据下,DRDS列式存储可以提供约3:1的压缩比。

下图解释的是列存的内存缓存行为。
image.png
列存的一大特点是只读取访问列相关的数据。在前面的例子中已经可以看到,通过统计信息可以减少从磁盘访问的数据量。在执行引擎的其他算子中,依然对应的策略减少无用的磁盘访问,以达到优化内存缓存行为的作用。在图中的Query例子中,JOIN算子在计算过程中,中只会试图缓存JOIN操作相关的列的数据。由于缓存资源有限,这种策略最大限度的提高了缓存的利用率。

DRDS列式存储当前的最佳实践:

  1. 避免极高TPS场景

写入一行,在行式存储是一次操作,由于列式存储的特性,需要总列数次操作。由于架构的特性的限制,无法做到与行存一致的极限事务能力。单表上的极限速度,INSERT可以达到5000TPS,UPDATE,DELETE约为1000TPS。通过DRDS分表策略(假设一台实例8个分库,一个分库4个分表),可达到的理论上限约为16万TPS和3万2千TPS。如果出现数据热点,总体同步延迟将上升,并伴随着总体TPS的下降。(此处的数据需要确认,后续需要给出可参考的值)

  1. 避免在单一实例上操作大量物理表

由于架构特性,列式存储通常在内存中留有缓冲区,用于积累新增数据。当缓冲区内的数据到达一定量的时候一次性写入磁盘,以缓解架构限制带来的DML性能问题。同时操作大量的表,会减少每一个表所能在内存中积累的数据量,进而使写盘更频繁的发生以造成性能下降。(后续需要给出可参考的值)。升级配置可以缓解这个现象。

  1. 避免在小表上进行大量UPDATE,DELETE

列式存储不能像行式存储一样在原地进行更新操作,所以采取了逻辑删除策略。即Update为逻辑删除+INSERT 新版本,DELETE为逻辑删除。逻辑会造成数据空洞,需要后台进程或系统维护期进行回收。在回收前,数据空洞会降低查询性能,并增加存储的压力。因此要避免在小数据量表上进行大量UPDATE,DELETE操作。

  1. 与索引的比较

多维过滤查询是列存的一大优势,然而在主实例上创建索引,通过行式的分析型只读实例也可以在一定程度上实现类似的目的。这两者的区别需要实现业务逻辑时加以注意。

  1. 增加索引会降低主实例的TP性能
  2. 如果查询条件组合比较多,可能会涉及到增加多个索引,使主实例的情况更加恶化
  3. 如果索引命中的数据量比较大,性能会衰退(通常不建议使用索引做只能剔除掉70或以下的查询)
  4. 相反,如果使用索引加上简单的过滤条件可以过滤掉95%以上的数据,并且在此之上并无更加复杂的操作,则推荐使用行式只读实例。
  5. 列式存储引擎对于查询条件复杂多变的情况更加适合
    1. 高QPS场景

与擅长OLTP型查询的行式执行引擎不同,列式执行引擎的设计目标是充分利用可用资源尽可能提高单条复杂查询的执行时间,而非让更多的查询并发的执行。另外,列式存储上通常执行的是全表扫描,相较于OLTP型数据库上的索引扫描(如果存在的话),即使在考虑了众多优化的前提下,消耗的资源依旧大很多。因此只有资源充足的情况下(例如需要访问的数据大部分都在缓存中),高QPS才可能实现。

  1. 尽量使用数值型

在技术上,DRDS列式存储可以在半压缩的数值类型数据上进行查询,相对于字符类型有很大的优势。另外执行引擎中大量使用的当前Intel最新的AVX-512指令集,进行向量化计算,因此对于数值类型的基本比较符,最高单核上亿行的计算能力。

  1. 减少无用的列访问

从架构特性上,列存的访问速度随访问列数的增加会有所下降。因此如有可能应避免“SELECT *”这一类操作,并在应用中,尽可能做到不SELECT不使用的列。

DRDS列式存储当前的使用限制:

  1. 不支持的数据类型
  2. 不支持的DDL操作