likes
comments
collection
share

为什么列式存储的数据库速度飞快

作者站长头像
站长
· 阅读数 55

前言

大家好,今天我想聊聊到底啥是列式存储,它凭啥速度飞快?自从 2015 年大数据崛起,我们常常听到列式存储这个名词。是不是会经常听到有人说 HBase 采用列式存储,性能查询提升了不止 100 倍。Cassandra 利用列式存储保证了一级数据秒级查询和更新。列式存储为大数据领域 TB 甚至 PB 级数据的实时查询和更新都提供了解决方案。

那么有的人可能就会问了,列式存储这么牛,那到底什么是列式存储呢?它和传统的行式存储有什么差别?接下来我就和你一起揭开列式存储的神秘面纱。

什么是列式存储

为什么列式存储的数据库速度飞快

首先我们要说的是,列式存储的概念不是从来就有的,它而是相对于行式存储而提出来的。像传统的关系型数据库,比如比如 Oracle、 MySQL、 SQLServer 等,都是以行来存储和读取数据。而这种基于行的数据的存取方式,在数据量不大的情况下,使用方便且运行良好。这里的数据量不大一般指数据级别在千万级内,但是在数据量动辄就在 TB 级和 PB 级的大数据领域,行式存储就显得力不从心了。因此为了解决海量数据的存储问题,我们提出了列式存储的概念。

首先我们先来看一下列式存储怎么理解。概念解释是这样的,列式数据库是以列相关的存储架构进行数据的存储的数据库,主要适合于批量数据处理和即时查询。大数据库的明星产品 HBase、Cassandra 等都采用列式存储的方式存储数据。

那么为什么大家都纷纷采用列式存储呢?因为我们的查询数据的条件都是通过列来定义的,所以整个数据库是自动化索引的。

列式存储的原理

前面我们介绍了列式存储的概念,接下来我们深入一起探讨一下列式存储的原理。只有理解弄清楚了原理,才能使我们对列式存储有个更全面的认识。但是在此之前我们还需要先回顾一下我们的行式存储。因为列式存储是相对于行式存储而提出来的,当了解了行式存储后,对列式存储的理解上也会变得更加简单。

为什么列式存储的数据库速度飞快

行式存储是以行为单位在磁盘上存储数据,因为大部分的 SQL 查询都是基于某个字段查询和结果输出的,所以在行式存储中每一次查询都存在着大量的磁盘转动和寻址操作。磁盘的转动次数多,因此它的查询性能能效率较慢。

假设我们有一张 user 表,表中有 id、userName、gender、age 4 个字段。当我们将表中的数据以行式存储的方式做存储在磁盘上时,它的存储结构是这样子的。

为什么列式存储的数据库速度飞快

可以看出行式存储将每个字段上的数据按行的方式存储在磁盘上的,例如第一条数据,它们对应的字段值都集中在磁盘的一个区域。同时我们也可以用图表的形式形象的表示行式存储在磁盘上的分布。

为什么列式存储的数据库速度飞快

同样我们可以看到 id 等于 1 的数据集中的存储在磁盘上前四位上,当我们执行一条 SQL 语句(select userName form user where gender='男'),查询 user 表中性别为男的用户名称时,在行式存储中查询的过程是这样的,系统首先从磁盘的第 3、7、11 位中找到 gender 等于男的数据,然后在每一条数据中查找并取得 name 字段的值。从这里可以知道,name 字段分别位于磁盘的第 2 和第 6 处。

从查询过程我们可以看出,由于 gender 属性跳跃的存储在磁盘上,因此在查询的时候磁盘需要多次转动才能找到对应的数据。同时由于 name 的属性值也跳跃的存储在磁盘上,因此磁头也需要多次长距离的移动才能找到 name 字段的数据并将结果输出。因此行式存储对磁盘的 IO 浪费比较大。

讲完了行式存储,相信你对行式的存储已经有了一定的认识和理解,这将帮助咱们更好的理解今天这节课的主角就是列式存储。

为什么列式存储的数据库速度飞快从列式存储在磁盘上的分布可以看到,列式存储是以列的形式在磁盘上存储数据的。

为什么列式存储的数据库速度飞快

同样的我们可以用图表的形式形象的表示列式存储明显可以看到列式存储以列的方式紧促的将数据存储在磁盘上。

那么问题来了,仅仅依靠数据的组织和存储方式的不一样,就能为我们的数据库的查询性能有百倍的提升吗?答案是肯定的。仔细想一想,我们的查询语句虽然五花八门,但所有的查询是不是都是基于某些特定字段进行查询?查询完之后是不是都是基于某些特定的字段进行结果的输出的呢?

因为列式存储它的数据是按照列来存储的,同一个列上的数据紧凑的存储在一起。所以相同的数据查询,列式存储只需要磁盘转动很少的次数就能命中数据。也就是说磁盘只需要很少的 IO 操作便能查询到数据。这也是列式存储比行式存储性能高上 100 倍的原因。并且它的查询在数据量越大时,它的性能表现越明显。

为了便于你理解,我们举个简单的例子,就比如当我们同样通过 SQL 查询 user 表中性别为男的用户名称(select userName form user where gender='男'),由于列中的 id 字段数据存储在 1、2、3 这 3 个连续的位置,userName 字段数据存储在 4、5、6 这 3 个连续的位置。因此在查询的时候,磁盘只需要很少次数的转动,磁头只需要短距离的移动,就能够找到对应的数据并将结果返回。

首先系统从磁盘的第 6 和第 7 位找到符合 gender 等于男的数据。我们可以看到由于第 6 位和第 7 位的数据在磁盘上是连续存储,因此磁盘的转动很少。然后在每条数据中获取了 userName 字段并返回。其中 userName 字段分别位于磁盘的第 3、4 两处。同样的道理,由于需要查询的 userName 字段连续的分布式在磁盘的的第 3 和第 4 位上。因此磁盘的转动也较小。

列式存储解决的问题

基于列式存储的特点,它能够很好的解决这两个问题。一个是“数据库不读取无效的数据”,提高了系统 IO 效率,还有一个就是提高数据的压缩比,节省磁盘空间。我们分别展开来讲一下。

首先从第一个问题开始,也就是“数据库不读取无效的数据”说起。由于列式存储,将同一个列上的数据存储在磁盘的连续的位置上。同时我们的查询通常是基于列来查询和展示的。因此列式存储在数据的查询过程中,只需要找到用户指定列的数据。比如说 select 中要返回的列和 where 条件中要查询的列,它不读取无效的数据,不但降低 IO 的开销,同时还提高了每每一次 IO 的效率,从而大大提高了查询性能。

为什么列式存储的数据库速度飞快

接下来我们举个例子说明一下,以便于咱们有个更深入的理解。假设有两张表,每张表数据大小为 100GB 且有 100 列,大多数查询只关心其中的几个列。采用列式存储,不需要像行式存储那样将整行的数据读取出,只需要取出需要的列。因此列式存储磁盘 IO 是行式存储的 10 分之 1 或者更少,查询响应时间可以提高十倍以上。

接下来我们看第二个问题,数据的压缩比。由于数据按照列来存储,每一个数据包内都是相同结构的数据,因此数据的内容相关性很高,这便使得数据库更易于实现压缩,压缩比通常能达到 10 分之 1 甚至更优。这使得能够同时在磁盘 IO 和 cache IO 上提高数据库的性能,进而使数据库在某些场景下的运算性能比传统的数据库快 100 倍甚至更多。因此列存储的 IO 优势就更加的明显了。

列式存储的数据更新

听到这里你是不是觉得只要使用了列式存储,数据库的性能就能有很大的提升呢?其实不是的,列式存储很好的解决了数据的快速查询问题,但是海量数据的存储更新,数据的删除问题并没有得到解决。不过幸运的是,我们针对这一系列问题,大数据服务的列式存储领域已经给出了很好的方案,并且是经过大规模的数据验证。但是好多人对它的理解还只停留在列式存储,在大数据领域查询效率很快,而不知道为什么它这么快,接下来我就给你详细分析一下海量数据快速存储、快速更新、快速删除的解决思路。

首先我们聊聊当有多列数据新增时,列式数据库是如何保证高效。以列式存储为基础的数据库,比如 HBase。Cassandra 等都有一个名叫 Column Family 的列,也就是列族,它们都是基于列族来划分数据的物理存储。一个列足可以包含任意多个列。当我们新增的数据位于多个列族时就可以并发的写磁盘,且在同一个列族内数据都是顺序存储的,在物理上对应一个 Block 块,因此这就保障了数据的快速新增

接下来我们聊一下列式数据库是如何保障数据快速的更新。比如 HBase、 Cassandra 这样的列式数据库,当数据更新操作时,只会在原有的数据基础上新加一条数据,并且更新这个数据的版本号。用户查询的时候默认查询版本号最新的一条数据。由于 HBase 和 Cassandra 这样基于标记更新的操作是顺序写磁盘的,其巧妙的避免了海量数据的查询更新和重建索引的流程。因此其数据的更新操作也很快。

最后我们看一下列式存储如何保障数据的快速删除。像 HBase、Cassandra 这样的列式数据库的删除操作。并不会立即从磁盘上删除。当执行删除操作时,数据库会新插入一条相同的 key-value 数据,但 keyType 等于 delete,这就意味着数据已经被删除了。当发生 Major_compaction 操作时,数据才会真正的从磁盘上删除。HBase 和 Cassandra 这种基于标记删除的方式,同样由于它是顺序写磁盘的,因此很容易的实现海量数据的快速删除。这也有效的避免了在海量数据库中查找、执行删除操作以及重建索引等复杂的流程。

总结

我们首先介绍了列式存储和行式存储的原理。通过原理我们可以得出两条结论。一条是列式存储,由于它在磁盘上是按照列存储数据的的,而我们数据读取也是通过列来读取的。因此它能够保障在最小的磁盘转动下快速的找到数据并返回,这有效的降低了 IO 开销,提高了系统查询效率。还有一条结论就是由于数据按照列来存储,每一个数据包都是同构的数据,数据的相关性很高,因此大大的提高了数据的压缩比例。

那么是不是仅仅通过列式存储就能够完全解决 TB 级数据的快速存取的呢?答案是否定的。我们还需要使用列族技术来保障数据存储的高效性。需要通过基于版本号的标记更新和标记删除,来保障基于顺序写磁盘模式下的更新和删除。这样就完美的解决了海量数据的增删改查等操作。

转载自:https://juejin.cn/post/7374055681890140195
评论
请登录