了解更多Greenplum技术干货,欢迎访问Greenplum中文社区网站
为了让查询更加有效,Greenplum引入了索引,但是索引在一些应用场景上也会有访问性能、过滤条件限制等问题,而位图和基于位图的访问很好的解决了这一问题。今天我们通过这篇文章提前来看一下Greenplum执行器的奥秘。
为什么需要位图扫描
首先来看一个普通的查询
SELECT sid FROM student WHERE enroll_year = 2017 OR enroll_year = 2018 OR enroll_year = 2019;
执行上面查询时,Greenplum最简单的方式可以采用对表student顺序扫描(Sequence Scan)。如果表student很大,并且查询只需要读取少量元组时,顺序扫描需要将全部元组从数据文件读出再进行过滤,这显然不是一个经济的方式。对此,Greenplum引入了索引,利用索引通过过滤条件可以很有效的定位到需要的元组,但是基于索引也会带来自身的问题。
第一个问题就是,如果结果元组比较多,但又没有到全部数据那么大的量级,通过索引访问元组会导致随机访问磁盘,访问性能上会差一个数量级。因为元组在磁盘上的存放顺序跟索引键的排序有可能是不同的,特别是对于存在多个索引的情况下。Greenplum期望能够做到基于结果集的顺序访问磁盘。
另外一个问题是,对于上面的查询语句,如果过滤条件是多个过滤条件的组合比如析取,无法直接利用索引进行查询。一个可能的解决办法是,可以通过各个查询条件分析到索引中查询到结果,再将所有结果“合并”到一起。通过最后“合并”后的结果进行查询。
所以,Greenplum引入了位图和基于位图的访问,位图中的第n位对应Greenplum中的第n个元组,通过位图中的1来表示对应元组命中,0表示跳过对应元组。如果将位图与元组的位置进行映射,就涉及到Greenplum元组的寻址问题。另外,Greenplum从索引接口上也直接支持返回满足条件元组的位图。
Greenplum元组的寻址与位图映射
Greenplum中的表,从存储格式上分为Heap表和AO表。Heap表支持频繁的元组更新和修改,结合磁盘读写的特点,为了效率,以页为单位进行访问。在Greenplum系统设计中,一个文件页是以32K (BLCKSZ)字节为大小,为物理磁盘页的整数倍。以32K字节为大小,在联机分析处理(OLAP)的场景下,可以获得较好的文件IO吞吐量,特别是对应顺序扫描的情况。上一节中讲到了表文件的分段存储,从逻辑上来看,对于同一个表的数据文件