引言
上一篇文章我对TIDScan算子作了解读,这篇文章里我将对和索引有关的BitmapScan包含的两个算子BitmapIndexScan算子和BitmapHeapScan算子简要解读。
代码位置
src\gausskernel\runtime\executor\nodeBitmapIndexscan.cpp
名词解释
bitmap(位图)
在C语言里,整形数类型有short、int、long long等,每一种类型拥有固定的大小。当需要存储一个长数组时,例如存储一个含有100000个元素的int型数组,需要耗费100000*4字节的空间,这对空间的开销无疑是巨大的。为了解决数组占用空间过大这一问题,我们引入bitmap(位图),bitmap是一串bit流,bit流中的每一个1代表对应的数字在数组中。
例如对于这样一串数组{0,2,3,5,6,7}对应的bitmap为1 0 1 1 0 1 1 1 0 0
,bitmap的第x位为1代表数字x-1在数组里面。
因此bitmap可以看做是一种映射机制,是从数组到bit流的一种映射。可以发现,bitmap相对于数组来说,不仅排序了,还去重了。
数据页
数据页是磁盘和内存交换的基本单位,也是GaussDB管理存储空间的基本单位。当需要读取某一数据时,如果内存中没有此数据,则需要在磁盘中读取数据所在页到内存。
示意图如下:
从磁盘中读取数据到内存中耗费的时间远远大于在内存中读取数据的时间。
功能作用
BitmapIndexScan
如果采用普通的B+树Index索引,很容易造成随机读取的情况。如下图所示
假设某一次查询最终定位到的索引值为虚线框内4个节点,这4个节点通过TID在表中查找到相应行数据。第一个TID对应表中第二行、第二个TID对应表中第七行以此类推。
假设一个数据页包含了Table中6行数据,上图中第1、3次读取是在第一个数据页里,第2、4次读取是在第二个数据页里,读取时总是在不同的数据页中跳转,不能很好地利用空间局部缓存。
使用BitmapScan可以一定程度上解决这个问题。
上文中提到,Bitmap带有自动排序和去重的功能。因此使用BitmapScan可以达到顺序读取的功能,如下图所示。
第一、二次读取在同一个数据页里面,第三、四次读取在另一个数据页里面。避免了读取数据时在数据页间随机访问来回跳转的问题。
事实上,因为有一些其他的考量,BitmapIndexScan里bitmap存的是行数据所在的数据页。还需要Recheck Cond操作对数据页中的元组过滤。
BitmapHeapScan
主要是对BitmapIndexScan返回的数据页Bitmap中的元组进行过滤,得到最终的索引元组。
小结
本篇文章中,我介绍了Bitmap的基本知识和与其有关的两个算子:BitmapIndexScan和BitmapHeapScan以及大致作用。下一篇文章我将开启控制算子Result的介绍。