mars3_brin 索引

本文介绍了 mars3_brin 索引的内部原理、相关函数及示例用法。

总述

mars3_brin 索引是 YMatrix 内置的稀疏型索引,全称为 MARS3 Block Range Index。它代表着一种基于块范围(Block Range)的索引结构。mars3_brin 索引将数据按块进行分组,并为每个块范围维护一个摘要值,而不是为每个行维护索引。它适用于有序数据集,如时间序列数据或连续范围的数据。

+-------------------+
|  BRIN Index      |
+-------------------+
|  Block Range 1   |
|  Block Range 2   |
|  Block Range 3   |
|       ...         |
|  Block Range N   |
+-------------------+

上图展示了 mars3_brin 索引的逻辑结构。该索引由多个块范围组成,一个块范围为一个索引单元,表示一段数据的范围。当你执行查询操作时,它可以通过跳过不符合查询条件的块范围(如查询项不属于该块范围的 minmax 值之间)来提高查询效率。

mars3_brin 索引通常以创建 MARS3 表时指定的排序键为索引键建立,以大幅提高 MARS3 表的查询性能。之所以在排序键上使用 mars3_brin 索引很有效,是因为数据在写入 MARS3 表时已根据建表指定的排序键排好了顺序,再建立索引时无需重新将表中数据排序,直接将内存中的有序列值和对应的 rowid(记录该数据值在内存中的物理位置,是唯一值)存进空闲的索引块即可。

内部原理

mars3_brin 索引中记录了每一个 range 的统计信息,比如各索引列中每一个 range 的 min/max 值及相应的 range ID 等(详见相关函数)。索引扫描首先通过 min/max 值判断该 range 的元组是否满足查询条件,若满足或者可能满足则获取该 range 的数据做进一步判断,否则扫描下一个 range。

YMatrix 通过 min/max 值来判断某 range 中的元组是否满足查询条件,具体如下:

  1. 首先,在你创建索引时,索引会自动记录每个索引项的最小值(min)和最大值(max),以便在数据更新时维护索引。

  2. 随后,在查询过程中,YMatrix 会使用查询条件中涉及的列的最小值和最大值与索引项的最小值和最大值进行比较。根据比较结果,可以确定哪些索引项可能满足查询条件:

    • 如果查询条件的最小值大于索引项的最大值,或者查询条件的最大值小于索引项的最小值,则可以确定该索引项不满足查询条件,可以跳过该索引项。
    • 如果查询条件的最小值小于等于索引项的最大值,且查询条件的最大值大于等于索引项的最小值,则需要进一步检查该索引项中的元组是否真正满足查询条件。这通常需要访问实际的数据行进行进一步的过滤。
  3. YMatrix 对于通过第二步确定的可能满足查询条件的索引项,访问对应的数据行,并检查这些数据行是否符合完整的查询条件。

相关函数

函数名 语法 参数 描述
mars3_info_brin SELECT * FROM matrixts_internal.mars3_info_brin('<索引名>'); 索引名 获取 mars3_brin 索引的统计信息(具体见下方返回字段)

该函数的返回字段:

字段 说明
segid Segment ID
level MARS3 的存储层级序号(0~9)
run MARS3 该存储层的存储单元序号
range 索引单元 range 的 ID(唯一标识)
placeholder 是否为行存数据预留占位符(true/false
attnum 列数量。普通列从 1 开始计数;系统列(例如 ctid)为负数
allnulls 是否都是空值(true/false
hasnulls 是否含有空值(true/false
value 该字段在所在 range 中的最小、最大值

示例用法

创建 matrixts 扩展。

=# CREATE EXTENSION matrixts;

创建 MARS3 表 t,包含列 c1c2

=# CREATE TABLE t(
c1 int,
c2 int)
USING MARS3
DISTRIBUTED BY (c1)
ORDER BY c1;

写入 10000 条随机数据。

=# INSERT INTO t (c1, c2)
SELECT FLOOR(RANDOM() * 100), FLOOR(RANDOM() * 100)
FROM (
    SELECT generate_series(1, 10000)
) AS dummy;

在排序键 c1 上创建 mars3_brin 索引。

=# CREATE INDEX t_index ON t USING mars3_brin(c1);

清理 t 表,使得 MARS3 的行存数据进入列存层级创建索引。索引只能在列存中创建。

=# VACUUM t;

查看索引 t_index 的详细信息。

=# SELECT * FROM matrixts_internal.mars3_info_brin('t_index');
 segid | level | run | range | placeholder | attnum | allnulls | hasnulls |   value
-------+-------+-----+-------+-------------+--------+----------+----------+------------
     0 |     1 |   2 |     0 | f           |      1 | f        | f        | {3 .. 99}
     0 |     1 |   3 |     0 | f           |      1 | f        | f        | {3 .. 51}
     0 |     1 |   3 |     1 | f           |      1 | f        | f        | {51 .. 93}
     0 |     1 |   3 |     2 | f           |      1 | f        | f        | {93 .. 99}
     2 |     1 |   2 |     0 | f           |      1 | f        | f        | {5 .. 73}
     2 |     1 |   3 |     0 | f           |      1 | f        | f        | {5 .. 58}
     2 |     1 |   3 |     1 | f           |      1 | f        | f        | {58 .. 73}
     3 |     1 |   2 |     0 | f           |      1 | f        | f        | {2 .. 96}
     3 |     1 |   3 |     0 | f           |      1 | f        | f        | {2 .. 37}
     3 |     1 |   3 |     1 | f           |      1 | f        | f        | {37 .. 92}
     3 |     1 |   3 |     2 | f           |      1 | f        | f        | {92 .. 96}
     1 |     1 |   2 |     0 | f           |      1 | f        | f        | {0 .. 98}
     1 |     1 |   3 |     0 | f           |      1 | f        | f        | {0 .. 49}
     1 |     1 |   3 |     1 | f           |      1 | f        | f        | {49 .. 83}
     1 |     1 |   3 |     2 | f           |      1 | f        | f        | {83 .. 98}
(15 rows)

另请参阅

MARS3 存储引擎