本章节主要为您介绍表格存储的表引擎、全局二级索引、以及多元索引。

表引擎

如上图所示,表格存储的数据模型采用宽行模型。不同的分区可以加载到不同的机器上,实现水平扩展。下面为您分析表格存储的模型特性以及基于模型的查询方式。

  • 多主键
    表格存储的宽表模型包含多个主键列,多列主键列按照顺序共同构成一个主键,类似MySQL的联合主键,也可以把多列主键列拼接起来看作HBase的RowKey,每一列其实都只是整体主键的一部分。采用多列主键主要原因如下:
    • 业务常需要多个字段来构成主键,如果只支持一个主键列,业务需要进行拼接,多列主键列避免了业务层做主键拼接和拆解。
    • 第一列主键列是分区键,使用分区键的范围进行分区划分,保证了分区键相同的行,一定在同一个分区上。分区键可以帮助实现分区内事务(Transection)、分区内自增列等功能。
    说明 主键的范围查询(GetRange接口)是指整体主键的范围,而非单独某一列的范围。
  • 模型优势
    • 完全水平扩展,可支撑的读写并发和数据规模几乎无上限。表格存储可支持千万级的PTS/QPS,以及10PB级的存储量。当业务数据量大量上涨时,只要增加机器资源即可。同时,基于共享存储的架构也实现了动态负载均衡,不需要数据库层进行副本数据复制。
    • 提供了表模型。相比纯粹的Key-value数据库,表格存储具有列和多版本的概念,可以单独对某列进行读写。表模型也是一种比较通用的模型,可以方便与其他系统进行数据模型映射。
    • 表模型中,按照主键有序存储,而非Hash映射,因此支持主键的范围扫描。类似于HashMap与SortedMap的区别(此模型类似于SortedMap)。
    • Schema Free,即每行可以有不同的属性列,数据列个数也不限制。适合存储半结构化的数据。业务在运行过程中,可以进行任意的属性列变更。
    • 支持数据自动过期和多版本。每列都可以存储多个版本的值,每个值会有一个版本号,同时也是一个时间戳,如果设置了数据自动过期,就会按照这个时间戳来判断数据是否过期,后台对过期数据自动清理。
  • 模型劣势
    • 数据查询依赖主键

      表格存储的数据模型类似于SortedMap,只能做点查和顺/逆序扫描,例如以下查询方式:

      • 主键点查

        通过已知主键,精确读取表上的一行。

      • 主键范围查

        按照顺序从开始主键(StartPrimaryKey)扫描到结束主键(EndPrimaryKey),或者逆序扫描。即对表进行顺序或逆序遍历,支持指定起始位置和结束位置。

      • 主键前缀范围查

        等价于主键范围查,主键前缀的一个范围可以转换成主键的一个范围,在表上进行顺序扫描即可。

    • 针对属性列的查询需要使用Filter

      Filter模式在过滤大量数据时效率有限,甚至变成全表扫描。数据查询的效率与底层扫描的数据量正相关,而底层扫描的数据量取决于数据分布和结构。数据默认仅按照主键有序存储,要按照某一属性列查询,符合条件的数据必然分布于全表的范围内,需要扫描后筛选。全表数据越多,扫描的数据量也就越大,效率也就越低。

在实际业务中,主键查询常常不能满足需求,而使用Filter在数据规模大的情况下效率很低,怎么解决这一问题呢?

数据查询的效率与底层扫描的数据量正相关,而Filter模式慢在符合条件的数据太分散,必须扫描大量的数据并从中筛选。解决这一问题也就有两种思路:
  • 让符合条件的数据不再分散分布

    使用全局二级索引,将某列或某几列作为二级索引的主键。相当于通过数据冗余,直接把符合条件的数据预先排在一起,查询时直接精确定位和扫描,效率极高。

  • 加快筛选的速度

    使用多元索引,多元索引底层提供了倒排索引、BKD-Tree等数据结构。以上面查询某属性列值为例,我们给这一列建立多元索引后,就会给这一列的值建立倒排索引,倒排索引实际上记录了某个值对应的所有主键的集合,即Value -> List。那么要查询属性列为某个Value的所有记录时,直接通过倒排索引获取所有符合条件的主键,进行读取即可。本质上是加快了从海量数据中筛选数据的效率。

全局二级索引

全局二级索引采用的仍然是表引擎,主表建立了全局二级索引后,相当于多了一张索引表。索引表相当于给主表提供了另外一种排序的方式,即针对查询条件预先设计了一种数据分布,来加快数据查询的效率。索引的使用方式与主表类似,主要的查询方式仍然是上面讲的主键点查、主键范围查、主键前缀范围查。

例如我们有一张表存储文件的MD5和SHA1值,表结构如下:

通过这张表,我们可以查询文件对应的MD5和SHA1值,但是通过MD5或SHA1反查文件名却不容易。我们可以给这张表建立两张全局二级索引表,表结构分别为:

图 1. 索引1
图 2. 索引2

为了确保主键的唯一性,全局二级索引会将原主键的主键列也放到主键列中,例如上面的FilePath列。有了上面两张索引表,就可以通过主键前缀范围查的方式里精确定位某个MD5/SHA1对应的文件名了。

多元索引

多元索引引擎相比于表引擎,底层增加了倒排索引,多维空间索引等,支持多条件组合查询、模糊查询、地理空间查询,以及全文索引等,还提供一些统计聚合能力。

倒排索引不仅可以解决单列值的检索问题,还可以解决多条件组合查询的问题。例如下表为一个订单记录:

上面一共16个字段,需要按照任意多个字段组合查询,例如查询某一售货员、某一产品类型、单价在xx元之上的所有记录。这样的排列组合会有非常多种,因此不太可能预先将任何一种查询条件的数据放到一起,来加快查询的效率,这需要建立很多的全局二级索引。而如果采用Filter模型,又很可能需要扫描全表,效率不高。折中的方式是,可以先对某个字段建立二级索引,缩小数据范围,再对其中数据进行Filter。那么有没有更好的方式呢?

多元索引可以很好的解决这一问题,而且只需要建立一个多元索引,将所有可能查询的列加入到这个多元索引中即可,加入的顺序也没有要求。多元索引中的每一列默认都会建立倒排,倒排就记录了Value到List的映射。针对多列的多个条件,在每列的倒排表中找到对应的List,这个称为一个倒排链,而筛选符合多个条件的数据即为计算多个倒排链的交并集,这里底层有着大量的优化,可以高效的实现这一操作。因此多元索引在处理多条件组合查询方面效率很高。

此外,多元索引还支持全文索引、模糊查询、地理空间查询等,以地理空间查询为例,多元索引通过底层的BKD-Tree结构,支持高效地查询一个地理多边形内的点,也支持按照地理位置排序、聚合统计等。