引言
Greenplum 是一款弱小而稳固的企业级分布式数据库。尽管基于 PostgreSQL,但 Greenplum 针对大数据的场景和用户对性能的极致谋求开发了大量的个性和做了极致甚至刻薄的优化。此外,Greenplum 严密拥抱 Postgres 社区,以麻利的形式疾速降级 Postgres 内核。在 Postgres 9.5 的内核中,Postgres 引入了一种全新的索引类型,名为 Brin Index,本文将具体介绍 Brin Index 的外部实现以及性能体现。
01 什么是 Brin Index
Brin 全称 Block Range Indexes,顾名思义即数据块范畴的索引,它的设计初衷是为了解决当数据表极其宏大时的迅速扫描问题。
家喻户晓,Heap 表以页面为单位进行组织,所以表的扫描也是以页面为单位。Brin 索引的根本思维就是在索引中记录一组间断页面中字段值的大抵统计信息,例如间断页面里某字段的最大值和最小值,页面扫描的时候依据 Brin 统计信息和查问条件间接跳过显著不合乎查问条件的页面,从而达到疾速扫描的成果。
在理论的查问打算中,位图扫描基于 Brin 索引实现整个扫描过程,如下所示:
gpadmin=# explain select * from t1 where c1 > 10 and c1 < 100;
-----------QUERY PLAN--------------
Gather Motion 3:1 (slice1; segments: 3) (cost=400.00..404.04 rows=1 width=64)
-> Bitmap Heap Scan on t1 (cost=400.00..404.02 rows=1 width=64)
Recheck Cond: ((c1 > 10) AND (c1 < 100))
-> Bitmap Index Scan on t1_idx_1 (cost=0.00..400.00 rows=1 width=0)
Index Cond: ((c1 > 10) AND (c1 < 100))
第一局部,Bitmap Index Scan 应用 Brin 索引和查问条件结构位图,记录无效页面并过滤掉绝大多数无用的页面,第二局部,Bitmap Heap Scan 基于位图精准扫描无效的页面并应用查问条件对页面内元组进行二次过滤。实际上,在 Brin 索引呈现之前,位图扫描通常应用 Btree 索引来结构位图,对于位图扫描的具体介绍,读者能够参考咱们的另外一篇文章 Greenplum 执行器位图——让查问更无效。
02 Heap 表的 Brin 索引实现
理解 Brin 索引实现的关键在于意识 Brin 索引文件的布局,Brin 索引文件同样以页为单位进行存储,其布局如下图所示:
从图中能够看到,Brin 索引文件中的页面有多种类型,其中比拟重要的是 Revmap 页和 Regular 页,Revmap 页中寄存这一个叫做页面范畴映射的构造(简称 revmap),其中的每一条记录都保留了 < 页面范畴 ID, Regular Page Tuple ID> 的映射关系。
一个页面范畴单位由 pages_per_range 参数来决定,默认是 128 个间断页面为一个页面范畴单位,用户在创立 Brin 索引的时候能够指定一个页面范畴的大小,例如:
create index idx_t1_id on t1 using brin (id) with (pages_per_range=64);
Regular Page 中寄存 Brin 索引元组, 不同于 Btree 索引,Brin 索引元组中保留着一个页面范畴单位对应的统计信息,例如 Min/Max,显然通过 Revmap 构造就能失去一个页面范畴及其对应的统计信息。
当一个页面范畴内的 Heap 页面增加了新的 tuple 并且新的 tuple 的值突破了该页面范畴原来的统计信息边界,咱们须要更新相应的 Brin 索引元组。当一个 tuple 从一个 Heap 页面删除时,咱们能够不更新其对应的 Brin 索引,这样会造成统计信息没有及时更新,然而正确性是没有问题的,在 Vacuum 的时候,Vaccum 会从新统计各个页面范畴的边界, 让索引信息更加的精确。
当 Bitmap Index Scan 构建位图的时候,咱们对 revmap 进行程序扫描,如果查问条件满足一个页面范畴的统计边界条件,那么该页面范畴内的所有页面都会用于构建位图,否则的话该页面范畴内的所有页面将会被跳过。
03 Brin 索引的性能体现
该局部咱们比照一下 Brin 索引和 Btree 索引。
首先创立一张表并插入数据
create table t1 (c1 int, c2 text, c3 text);
insert into t1 select i, 'ssfesregeugruehpeoghregygeye', 'frheuogygryeosihfuiewhurheuhre' from generate_series(1, 10000000) i;
gpadmin=# \d+
List of relations
Schema | Name | Type | Owner | Storage | Size | Description
--------+------+-------+---------+---------+--------+-------------
public | t1 | table | gpadmin | heap | 881 MB |
(1 row)
能够看到 t1 表的大小大概在 900MB 左右。
同时在 t1 上创立 Brin 索引和 Btree 索引。
create index t1_idx_1 on t1 using brin(c1);
create index t1_idx_2 on t1 using btree(c1);
gpadmin=# \di+
List of relations
Schema | Name | Type | Owner | Table | Size | Description
--------+----------+-------+---------+-------+--------+-------------
public | t1_idx_1 | index | gpadmin | t1 | 768 kB |
public | t1_idx_2 | index | gpadmin | t1 | 213 MB |
能够看到,Brin 索引的大小仅为 768KB,而 Btree 索引的大小为 213MB,显然在索引大小上,Brin 索引有较大的劣势,这也是 Brin 索引最大的一个特点,尤其当数据表及其大的时候,Brin 索引的大小劣势会显得极其吸引人。
同时,Brin 索引在查问性能方面也有不错的晋升。
当不应用索引的状况下,上面查问耗时 4080ms。
gpadmin=# select count(*) from t1 where c1 > 10 and c1 < 1000;
count
-------
989
(1 row)
Time: 4080.735 ms
当应用 Brin 索引时,同样查问耗时 58ms。
gpadmin=# select count(*) from t1 where c1 > 10 and c1 < 1000;
count
-------
989
(1 row)
Time: 58.739 ms
当应用 Btree 索引时,同样的查问耗时 4ms。
gpadmin=# select count(*) from t1 where c1 > 10 and c1 < 1000;
count
-------
989
(1 row)
Time: 3.738 ms
思考到 Brin 索引是一个范畴索引,其具备肯定的稠密性,索引的精度在一些状况下不如 Btree 索引,下面的性能差距能够了解。尽管如此,咱们也看到 Brin 索引绝对于程序扫描还是获得了微小的性能晋升,这也体现了 Brin 索引的价值。
04 结语
Brin 索引作为一个新的索引类型,具备极具劣势的磁盘空间体现以及优良的查问性能体现,同时还具备比拟好的索引更新性能,这些个性非常合乎超大型数据表的要求,在事实利用中被大家宽泛的应用,本文简略介绍了 Brin 索引及其实现,心愿对大家了解索引有所帮忙。