Bitmap索引

大部分转自http://www.west.cn/cms/wiki/code/2018-07-20/41456.html

Bitmap索引到底是个神马

Bitmap称为位图

举个简单的例子来演示如何使用Bitmap Index来加速数据库的多维查询性能。下图是一张典型的时序数据表:

Timestamp

Page

Username

Gender

City

Added

Removed

2011-01-01T01:00:00Z 

Justin Bieber

Boxer

Male

San Francisco

1800

25

2011-01-01T01:00:00Z 

Justin Bieber

Reach

Female

Taiyuan

2912

42

2011-01-01T02:00:00Z 

Ke$ha

Helz

Female

Calgary 

1953

17

2011-01-01T02:00:00Z 

Ke$ha

Xeno

Male

Taiyuan

3194

170

图中Timestamp列是时序列,Page、Username、Gender和City这几个列是维度列,Added以及Removed两列是数值列。基于这样的原始表,可以构造一个典型的多维查询如下:

select Added from datasource where Gender = ‘Female’ and City = ‘Taiyuan’

查询中使用两个维度条件进行过滤,分别是Gender以及City列。很显然,如果不使用任何技术手段的话,在原始表上根据如上两个维度的过滤条件进行查询需要遍历整个原始表,并对相应维度列进行过滤,这个代价很显然是非常可观的。那能不能有一种方法可以直接根据维度的过滤条件得到待查找目标行,比如上述示例中能不能根据Gender = ‘Female’ and City = ‘Taiyuan’这两个过滤条件直接定位到待查找目标行就是第二行,其他行都不满足条件,这样的话只需要查找第二行的Added列返回给用户即可,不再需要野蛮的全表扫描并一条一条数据进行对比。这就是Bitmap索引(倒排索引)的使命!

使用Bitmap索引的基本原理是将这两列上的数值映射到bitmap上,再采用intersection表示来实现and、or等这种查询谓词。在上述示例中,将Gender以及City两列映射成bitmap如下图所示:

它不是将值存进去,它就是用数据的索引来表示行数,用0,1来表示这一行是不是Male(举例),如果是Male,则值为1,以上图的例子来讲,就是第一行跟第4行是Male,因为它的值是1

原始表中,Gender列中有两个值:Male和Female,因此需要设置两个对应的bitmap,Male分配一个,Female分配一个,两个bitmap的大小对应原始表的数据行数,原始数据有4行,bitmap的大小就是4。再看原始表的Gender列,行1和行4是Male,行2和行3是Female。因此将Male对应的bitmap中坐标为1和4的值置为1,其他两位置为0。Female对应的bitmap中坐标为2和3的值置为1,其他两位置为0。

这样的bitmap表示什么意思呢?以Male对应的bitmap来说,下标是1和4的值为1就表示原始表中这一列的第一行和第4行的值为Male。同理,Female对应的bitmap中下标是2和3对应的值为1表示原始表中这一列的第2行和第3行的值为Female。同样的道理,City列可以表示为上图右侧3个bitmap。

可见,每个维度列有多少种取值(Cardinality),这个维度列就会有多少个Bitmap。每个Bitmap表示对应取值在原始表中哪些行出现过。

这样表示完成之后,再来看看查询语句:where Gender = ‘Female’ and City = ‘Taiyuan’,就可以使用对应bitmap表示为如下形式:

分别拿出 Gender = ‘Female’ and City = ‘Taiyuan’ 对应的bitmap,执行and操作实际上对应位图的与运算,最终得到一个结果位图,结果位图中只有下标2的值置为1,说明原始表中满足查询条件的行只有第二行

综上:真的是很巧妙的思路

一个关键的点:每个维度列实际上都会维护一个Bitmap数组:MutableBitmap[],数组大小为每个维度列的可取值多少(Cardinality),比如Gender列只有Male和Female两个取值,Bitmap数组大小就为2。数组的第一个值为Male对应的位图数据,数组的第二个值为Female对应的位图数据。这里就有一个问题,为什么说数组的第一个值是Male对应的位图数据,而不是第二个值呢?这就是用到了上文中提到的维度字典,Male对应的维度字典值为0,就对应数组下标为0;Female对应的维度字典值为1,对应数据下标就为1。

下面以其中一行数据为例介绍构建Bitmap索引的过程:

1. 首先会为每一行生成一个自增的rowNum

2. 遍历所有维度列,分别为每个维度列构建相应的Bitmap数组

  • 针对某个纬度列的value值,首先在维度字典中根据value找到对应的id,这个id即是Bitmap数组的下标,根据这个下标找到该value对应的位图数据,即MutableBitmap[id]
  • 定位到位图数据之后,再将该位图下标为rowNum的bit位置为1

为了更加具体地理解整个Bitmap索引构建的过程,我们以上文中Gender维度列为例模拟构建的过程:

1. Gender维度列会维护了一个位图数组MutableBitmap[] bitmaps,里面有两个位图元素,下标为0的是Male对应的bitmap,下标为1的是Female对应的bitmap。初始时这两个bitmap中都没有任何数字。

2. 遍历第一行(rowNum = 0),值为Male,根据维度字典找到对应的id位0,即Male对应的位图数据为bitmaps[0],将bitmaps[0]下标0(rowNum为0)的bit位置为1,得到:

3. 遍历第二行(rowNum = 1),值为Female,根据维度字典找到对应的id位1,即Male对应的位图数据为bitmaps[1],将bitmaps[1]下标1(rowNum为1)的bit位置为1,得到:

4. 遍历第三行(rowNum = 2),值为Female,根据维度字典找到对应的id位1,即Male对应的位图数据为bitmaps[1],将bitmaps[1]下标2(rowNum为2)的bit位置为1,得到:

5. 遍历第一行(rowNum = 3),值为Male,根据维度字典找到对应的id位0,即Male对应的位图数据为bitmaps[0],将bitmaps[0]下标3(rowNum为3)的bit位置为1,得到:

这样,就可以得到Gender维度列的Bitmap索引。当然,遍历一行数据时,同时会为所有其他维度列构建Bitmap索引,上述过程仅以Gender维度列作为示例,其他维度列同理可得。

猜你喜欢

转载自blog.csdn.net/AAA821/article/details/81985874