71.3. 可扩展性#
BRIN接口具有很高的抽象级别,要求访问方法实现者仅实现正在访问的数据类型的语义。BRIN层本身负责并发、日志记录和搜索索引结构。
要使BRIN访问方法正常工作,只需实现一些用户定义的方法,这些方法定义了存储在索引中的摘要值的特性以及它们与扫描键交互的方式。简而言之,BRIN将可扩展性与通用性、代码重用和简洁的界面相结合。
对于BRIN,操作符类必须提供四种方法
BrinOpcInfo *opcInfo(Oid type_oid)
返回有关索引列摘要数据的内部信息。返回值必须指向一个已分配的
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 是否与范围的给定索引值一致。作为扫描键的一部分传递要使用的属性编号。这是与向后兼容的较旧一致函数变体。
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()
宏从其他支持函数访问这些选项。由于索引值的键提取和 中键的表示都是灵活的,因此它们可能取决于用户指定的参数。
核心发行版包括对四种类型的运算符类的支持:minmax、minmax-multi、inclusion 和 bloom。根据需要,使用它们的操作符类定义会运用于内核数据类型。用户可以使用等效的定义为其他数据类型定义其他运算符类,而无需编写任何源代码;声明适当的目录条目就足够了。请注意,运算符策略语义的假设已嵌入到支持函数的源代码中。
实现完全不同语义的运算符类也是可能的,前提是编写了上面描述的四个主要支持函数的实现。请注意,不保证主要版本之间的向后兼容性:例如,在以后的版本中可能需要其他支持函数。
要为实现完全有序集的数据类型编写运算符类,可以使用 minmax 支持函数以及相应的运算符,如表 71.2所示。所有运算符类成员(函数和运算符)都是必需的。
表 71.2. Minmax 运算符类的函数和支持编号
运算符类成员 | 对象 |
---|---|
支持函数 1 | 内部函数 brin_minmax_opcinfo() |
支持函数 2 | 内部函数 brin_minmax_add_value() |
支持函数 3 | 内部函数 brin_minmax_consistent() |
支持函数 4 | 内部函数 brin_minmax_union() |
运算符策略 1 | 运算符小于 |
运算符策略 2 | 运算符小于或等于 |
运算符策略 3 | 运算符等于 |
运算符策略 4 | 运算符大于或等于 |
运算符策略 5 | 运算符大于 |
要为包含在另一种类型中的值的复杂数据类型编写运算符类,可以使用包含支持函数以及相应的运算符,如表 71.3中所示。它只需要一个附加函数,该函数可以用任何语言编写。可以定义更多函数以获得更多功能。所有运算符都是可选的。某些运算符需要其他运算符,如表中所示的依赖项。
表 71.3. 包含运算符类的函数和支持编号
运算符类成员 | 对象 | 依赖项 |
---|---|---|
支持函数 1 | 内部函数 brin_inclusion_opcinfo() | |
支持函数 2 | 内部函数 brin_inclusion_add_value() | |
支持函数 3 | 内部函数 brin_inclusion_consistent() | |
支持函数 4 | 内部函数 brin_inclusion_union() | |
支持函数 11 | 合并两个元素的函数 | |
支持函数 12 | 可选函数,用于检查两个元素是否可合并 | |
支持函数 13 | 可选函数,用于检查一个元素是否包含在另一个元素中 | |
支持函数 14 | 可选函数,用于检查一个元素是否为空 | |
运算符策略 1 | 运算符位于左侧 | 运算符策略 4 |
运算符策略 2 | 运算符不延伸到右侧 | 运算符策略 5 |
运算符策略 3 | 运算符重叠 | |
运算符策略 4 | 运算符不延伸到左侧 | 运算符策略 1 |
运算符策略 5 | 运算符位于右侧 | 运算符策略 2 |
运算符策略 6、18 | 运算符相同或相等 | 运算符策略 7 |
运算符策略 7、16、24、25 | 运算符包含或相等 | |
运算符策略 8、26、27 | 运算符被包含或相等 | 运算符策略 3 |
运算符策略 9 | 运算符不延伸到上方 | 运算符策略 11 |
运算符策略 10 | 运算符位于下方 | 运算符策略 12 |
运算符策略 11 | 运算符位于上方 | 运算符策略 9 |
运算符策略 12 | 运算符不延伸到下方 | 运算符策略 10 |
运算符策略 20 | 运算符小于 | 运算符策略 5 |
运算符策略 21 | 运算符小于或等于 | 运算符策略 5 |
运算符策略 22 | 运算符大于 | 运算符策略 1 |
运算符策略 23 | 运算符大于或等于 | 运算符策略 1 |
支持功能编号 1 到 10 保留给 BRIN 内部功能,因此 SQL 级别功能从编号 11 开始。支持功能编号 11 是构建索引所需的主要功能。它应接受两个与运算符类相同数据类型参数,并返回它们的并集。如果包含运算符类使用STORAGE
参数定义,则它可以存储具有不同数据类型的并集值。并集函数的返回值应与STORAGE
数据类型匹配。
提供支持功能编号 12 和 14 以支持内置数据类型的异常。功能编号 12 用于支持不可合并的不同系列的网络地址。功能编号 14 用于支持空范围。功能编号 13 是可选的,但建议使用,它允许在将新值传递给并集函数之前对其进行检查。由于 BRIN 框架可以在并集未更改时对某些操作进行快捷处理,因此使用此功能可以提高索引性能。
要为仅实现相等运算符并支持哈希的数据类型编写运算符类,可以使用布隆支持过程以及相应运算符,如表 71.4所示。所有运算符类成员(过程和运算符)都是必需的。
表 71.4。布隆运算符类的过程和支持编号
运算符类成员 | 对象 |
---|---|
支持过程 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 允许汇总到多个较小的区间,以更好地处理异常值。可以使用 minmax-multi 支持过程以及相应运算符,如表 71.5所示。所有运算符类成员(过程和运算符)都是必需的。
表 71.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 和包含运算符类都支持跨数据类型的运算符,但依赖关系会变得更复杂。minmax 运算符类要求定义一组完整的运算符,其中两个参数具有相同的数据类型。它允许通过定义额外的运算符集来支持其他数据类型。包含运算符类运算符策略依赖于另一个运算符策略,如表 71.3所示,或与它们自己相同的运算符策略。它们要求使用STORAGE
数据类型作为左侧参数,并使用另一个受支持的数据类型作为受支持运算符的右侧参数来定义依赖运算符。请参阅float4_minmax_ops
作为 minmax 的示例,并参阅box_inclusion_ops
作为包含的示例。