BRIN 接口具有较高层次的抽象,访问方法实现者只需实现被访问数据类型的语义。 BRIN 层本身负责并发、日志记录以及搜索索引结构。
要让一种 BRIN 访问方法工作起来,只需实现少数几个用户定义的方法, 它们定义索引中存储的摘要值的行为,以及这些摘要值与扫描键之间的交互。 简言之,BRIN 把可扩展性与通用性、代码重用以及清晰的接口结合在一起。
BRIN 操作符类必须提供以下四个方法:
BrinOpcInfo *opcInfo(Oid type_oid)返回被索引列的摘要数据的内部信息。返回值必须指向一个用 palloc 分配的 BrinOpcInfo,其定义如下:
typedef struct BrinOpcInfo
{
/* Number of columns stored in an index column of this opclass */
uint16 oi_nstored;
/* Opaque pointer for the opclass' private use */
void *oi_opaque;
/* Type cache entries of the stored columns */
TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER];
} BrinOpcInfo;
BrinOpcInfo.oi_opaque 可供操作符类例程在索引扫描期间于各个支持函数之间传递信息。
bool consistent(BrinDesc *bdesc, BrinValues *column, ScanKey *keys, int nkeys)返回所有 ScanKey 条目是否都与某个范围给定的索引值一致。 要使用的属性编号作为扫描键的一部分传入。 同一属性的多个扫描键可以一次传入;条目数量由 nkeys 参数决定。
bool consistent(BrinDesc *bdesc, BrinValues *column, ScanKey key)返回该 ScanKey 是否与某个范围给定的索引值一致。 要使用的属性编号作为扫描键的一部分传入。 这是 consistent 函数较旧的向后兼容变体。
bool addValue(BrinDesc *bdesc, BrinValues *column, Datum newval, bool isnull)给定一个索引元组和一个被索引值,修改该元组中指定的属性,使其能够额外表示这个新值。 如果对该元组做了任何修改,就返回 true。
bool unionTuples(BrinDesc *bdesc, BrinValues *a, BrinValues *b)合并两个索引元组。给定两个索引元组,修改第一个元组中指定的属性,使其能够表示这两个元组。 第二个元组不会被修改。
BRIN 操作符类还可以选择指定下列方法:
void options(local_relopts *relopts)定义一组控制操作符类行为的用户可见参数。
options 函数会接收一个指向 local_relopts 结构的指针,需要用一组操作符类专用选项填充它。 这些选项可以通过 PG_HAS_OPCLASS_OPTIONS() 和 PG_GET_OPCLASS_OPTIONS() 宏从其他支持函数中访问。
由于被索引值的键提取以及 BRIN 中键的表示都具有灵活性, 它们可能依赖于用户指定的参数。
核心发行版包含四种操作符类支持:minmax、minmax-multi、inclusion 和 bloom。 针对核心数据类型,发行版会酌情附带使用它们的操作符类定义。 用户也可以为其他数据类型定义等价的操作符类,而无需编写任何源代码;只要声明适当的系统目录项即可。 注意,对操作符策略语义的某些假设嵌入在支持函数的源码中。
只要为上文所述的四个主要支持函数编写实现,也可以实现语义完全不同的操作符类。 注意,不保证跨主版本的向后兼容性:例如,在后续版本中可能需要附加的支持函数。
要为实现全序集的数据类型编写操作符类,可以按 Table 66.2 所示,将 minmax 支持函数与相应操作符一起使用。 所有操作符类成员(函数和操作符)都是必需的。
Table 66.2. Minmax 操作符类的函数和支持编号
| 操作符类成员 | 对象 |
|---|---|
| 支持函数 1 | 内部函数brin_minmax_opcinfo() |
| 支持函数 2 | 内部函数brin_minmax_add_value() |
| 支持函数 3 | 内部函数brin_minmax_consistent() |
| 支持函数 4 | 内部函数brin_minmax_union() |
| 操作符策略 1 | 小于操作符 |
| 操作符策略 2 | 小于等于操作符 |
| 操作符策略 3 | 等于操作符 |
| 操作符策略 4 | 大于等于操作符 |
| 操作符策略 5 | 大于操作符 |
要为一种值能够被包含在另一种类型中的复杂数据类型编写操作符类, 可以按 Table 66.3 所示, 将 inclusion 支持函数与相应操作符一起使用。 它只需要额外一个函数,而且该函数可以用任何语言编写。 还可以定义更多函数以提供附加功能。 所有操作符都是可选的。某些操作符依赖其他操作符,表中已列出这些依赖关系。
Table 66.3. Inclusion 操作符类的函数和支持编号
| 操作符类成员 | 对象 | 依赖关系 |
|---|---|---|
| 支持函数 1 | 内部函数brin_inclusion_opcinfo() |
|
| 支持函数 2 | 内部函数brin_inclusion_add_value() |
|
| 支持函数 3 | 内部函数brin_inclusion_consistent() |
|
| 支持函数 4 | 内部函数brin_inclusion_union() |
|
| 支持函数 11 | 合并两个元素的函数 | |
| 支持函数 12 | 可选函数,检查两个元素是否可以合并 | |
| 支持函数 13 | 可选函数,检查一个元素是否被包含在另一个中 | |
| 支持函数 14 | 可选函数,用于检查元素是否为空 | |
| 操作符策略 1 | left-of 操作符 | 操作符策略 4 |
| 操作符策略 2 | does-not-extend-to-the-right-of 操作符 | 操作符策略 5 |
| 操作符策略 3 | overlaps 操作符 | |
| 操作符策略 4 | does-not-extend-to-the-left-of 操作符 | 操作符策略 1 |
| 操作符策略 5 | right-of 操作符 | 操作符策略 2 |
| 操作符策略 6, 18 | same-as-or-equal-to 操作符 | 操作符策略 7 |
| 操作符策略 7, 16, 24, 25 | contains-or-equal-to 操作符 | |
| 操作符策略 8, 26, 27 | is-contained-by-or-equal-to 操作符 | 操作符策略 3 |
| 操作符策略 9 | does-not-extend-above 操作符 | 操作符策略 11 |
| 操作符策略 10 | is-below 操作符 | 操作符策略 12 |
| 操作符策略 11 | is-above 操作符 | 操作符策略 9 |
| 操作符策略 12 | does-not-extend-below 操作符 | 操作符策略 10 |
| 操作符策略 20 | 小于操作符 | 操作符策略 5 |
| 操作符策略 21 | 小于等于操作符 | 操作符策略 5 |
| 操作符策略 22 | 大于操作符 | 操作符策略 1 |
| 操作符策略 23 | 大于等于操作符 | 操作符策略 1 |
支持函数编号 1 到 10 保留给 BRIN 内部函数,因此 SQL 层函数从编号 11 开始。 支持函数 11 是构建索引所需的主要函数。 它应接受两个与操作符类数据类型相同的参数,并返回它们的并集。 如果 inclusion 操作符类在定义时使用了 STORAGE 参数, 则它可以存储具有不同数据类型的并集值。 并集函数的返回值应与 STORAGE 数据类型匹配。
支持函数 12 和 14 用于处理内置数据类型中的不规则情况。 函数 12 用于支持来自不同地址族、无法合并的网络地址。 函数 14 用于支持空范围。 函数 13 是可选但推荐的;它允许在把新值传给并集函数之前先进行检查。 由于 BRIN 框架在并集未发生变化时可以跳过某些操作,使用这个函数可以提升索引性能。
要为仅实现等值操作符且支持哈希的数据类型编写操作符类,可以按 Table 66.4 所示,将 bloom 支持过程与相应操作符一起使用。 所有操作符类成员(过程和操作符)都是必需的。
Table 66.4. bloom 操作符类的过程和支持编号
| 操作符类成员 | 对象 |
|---|---|
| 支持过程 1 | 内部函数brin_bloom_opcinfo() |
| 支持过程 2 | 内部函数brin_bloom_add_value() |
| 支持过程 3 | 内部函数brin_bloom_consistent() |
| 支持过程 4 | 内部函数brin_bloom_union() |
| 支持过程 5 | 内部函数brin_bloom_options() |
| 支持过程 11 | 计算元素哈希值的函数 |
| 操作符策略 1 | 等于操作符 |
支持过程编号 1 至 10 保留给 BRIN 内部函数,因此 SQL 层函数从编号 11 开始。 支持函数 11 是构建索引所需的主要函数。 它应接受一个与操作符类数据类型相同的参数,并返回该值的哈希值。
minmax-multi 操作符类也面向实现全序集的数据类型,可以看作 minmax 操作符类的简单扩展。 minmax 操作符类把每个块范围中的值摘要为单个连续区间,而 minmax-multi 则允许将其摘要为多个较小区间,以改进对离群值的处理。 可以按 Table 66.5 所示,将 minmax-multi 支持过程与相应操作符一起使用。 所有操作符类成员(过程和操作符)都是必需的。
Table 66.5. minmax-multi 操作符类的过程和支持编号
| 操作符类成员 | 对象 |
|---|---|
| 支持过程 1 | 内部函数brin_minmax_multi_opcinfo() |
| 支持过程 2 | 内部函数brin_minmax_multi_add_value() |
| 支持过程 3 | 内部函数brin_minmax_multi_consistent() |
| 支持过程 4 | 内部函数brin_minmax_multi_union() |
| 支持过程 5 | 内部函数brin_minmax_multi_options() |
| 支持过程 11 | 计算两个值之间距离(范围长度)的函数 |
| 操作符策略 1 | 小于操作符 |
| 操作符策略 2 | 小于等于操作符 |
| 操作符策略 3 | 等于操作符 |
| 操作符策略 4 | 大于等于操作符 |
| 操作符策略 5 | 大于操作符 |
minmax 和 inclusion 操作符类都支持跨数据类型操作符,但这样依赖关系会更加复杂。 minmax 操作符类要求定义一整套两侧参数都具有相同数据类型的操作符。 它还允许通过定义额外的操作符集合来支持附加数据类型。 如 Table 66.3 所示, inclusion 操作符类的操作符策略依赖于另一种操作符策略,或者依赖于它们自身对应的同名操作符策略。 这要求把依赖操作符定义为:左侧参数是 STORAGE 数据类型, 右侧参数是其他受支持的数据类型。 minmax 的示例见 float4_minmax_ops,inclusion 的示例见 box_inclusion_ops。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。