BRIN接口具有高层的抽象,要求访问方法实现者只需 实现被访问的数据类型的语义。BRIN层本身会负责并 发、日志以及对索引结构的搜索。
让一种BRIN访问方法能够工作要做的全部事情是实现 几个用户定义的方法, 它们定义存储在索引中的摘要值的行为以及它们和扫描键 的交互。简而言之,BRIN很好地把可扩展性和通用性、 代码重用以及干净的接口结合在了一起。
BRIN的一个操作符类必须提供四种方法:
BrinOpcInfo *opcInfo(Oid type_oid)
返回有关被索引列的摘要数据的内部信息。返回值必须指向一个已经 palloc
的BrinOpcInfo
,该结构的定义是:
typedef struct BrinOpcInfo { /* 这个 opclass 的一个索引列中存储的列数 */ uint16 oi_nstored; /* 该 opclass 私有用途的不透明指针 */ void *oi_opaque; /* 被存储列的类型缓冲项 */ 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。 发布中也酌情为核心中的数据类型提供了使用它们的操作符类定义。 用户可以用等效的定义为其他数据类型定义额外的操作符类,而不需要编写任何源代码,只需要声明一些适当的目录项就足够了。 注意有关操作符策略的语义的假设是嵌在支持函数的源代码中的。
实现完全不同的语义的操作符类也是可能的,只要提供上述的四个主要支持过程的实 现即可。注意在主要发行版之间的向后兼容性是不被保证的:例如,在以后的发行中 可能要求额外的支持过程。
要为一种实现了线性有序集的数据类型编写一个操作符类,可以使用 minmax 支持函数配上对应的操作符(如表 68.2所示)。 所有的操作符类成员(函数和操作符)都是强制性的。
表 68.2. Minmax 操作符类的函数和支持编号
操作符类成员 | 对象 |
---|---|
支持函数 1 | 内部函数brin_minmax_opcinfo() |
支持函数 2 | 内部函数brin_minmax_add_value() |
支持函数 3 | 内部函数brin_minmax_consistent() |
支持函数 4 | 内部函数brin_minmax_union() |
操作符策略 1 | 小于操作符 |
操作符策略 2 | 小于等于操作符 |
操作符策略 3 | 等于操作符 |
操作符策略 4 | 大于等于操作符 |
操作符策略 5 | 大于操作符 |
要为值被包括在另一种类型的复杂数据类型编写操作符类,可以使用 inclusion 支持函数配上相应的操作符(如 表 68.3所示)。它只要求一个 可用任何语言编写的附加函数。可以定义更多函数来提供额外的功能。所有的 操作符都是可选的。如该表中的依赖性所示,某些操作符需要其他操作符。
表 68.3. Inclusion 操作符类的函数和支持编号
操作符类成员 | 对象 | 依赖性 |
---|---|---|
支持函数 1 | 内部函数brin_inclusion_opcinfo() | |
支持函数 2 | 内部函数brin_inclusion_add_value() | |
支持函数 3 | 内部函数brin_inclusion_consistent() | |
支持函数 4 | 内部函数brin_inclusion_union() | |
支持函数 11 | 合并两个元素的函数 | |
支持函数 12 | 可选函数,检查两个元素是否可以合并 | |
支持函数 13 | 可选函数,检查一个元素是否被包含在另一个中 | |
支持函数 14 | optional function to check whether an element is empty | |
操作符策略 1 | 位于左边操作符 left-of | 操作符策略 4 |
操作符策略 2 | 不超过左边操作符 does-not-extend-to-the-right-of | 操作符策略 5 |
操作符策略 3 | 重叠操作符 | |
操作符策略 4 | 不超过左边操作符 does-not-extend-to-the-left-of | 操作符策略 1 |
操作符策略 5 | 位于右边操作符 right-of | 操作符策略 2 |
操作符策略 6, 18 | 相同或者等于操作符 | 操作符策略 7 |
操作符策略 7, 16, 24, 25 | 包含或等于操作符 | |
操作符策略 8, 26, 27 | 被包含或等于操作符 | 操作符策略 3 |
操作符策略 9 | 不超过上边操作符 does-not-extend-above | 操作符策略 11 |
操作符策略 10 | 操作符 is-below | 操作符策略 12 |
Operator Strategy 11 | 在上面操作符 is-above | 操作符策略 9 |
操作符策略 12 | 不超过下面操作符 does-not-extend-below | 操作符策略 10 |
操作符策略 20 | 小于操作符 | 操作符策略 4 |
操作符策略 21 | 小于等于操作符 | 操作符策略 4 |
操作符策略 22 | 大于操作符 | 操作符策略 1 |
操作符策略 23 | 大于等于操作符 | 操作符策略 1 |
支持过程编号 1 至 10 被保留给 BRIN 的内部函数,因此 SQL 层面的函数从
编号 11 开始。支持函数编号 11 是用于构建该索引的主要函数。它应该接
受两个具有和操作符类相同数据类型的参数并且返回它们的并集。如果
inclusion 操作符类定义时用了STORAGE
参数,则它可以存储具有
不同数据类型的合并值。该并集函数的返回值应该匹配
STORAGE
的数据类型。
支持函数编号 12 和 14 被提供用来支持内建数据类型的不规则性。函数编号 12 被用来支持来自不同地址族的不能合并的网络地址。函数编号 14 被用来 支持空范围。函数编号 13 是可选的,但是我们推荐提供它。它允许在新值 被传递给并集函数前对其进行检查。因为 BRIN 框架在并集没有改变时可以 越过某些操作,所以使用这个函数可以提升索引性能。
为仅实现相等运算符并且支持哈希的数据类型编写运算符类, 可以将bloom支持过程与相应的操作程序一起使用, 就像 表 68.4中所列出的。 所有的操作符类成员(过程和操作符)都是强制性的。
表 68.4. 布隆操作符类的过程和支持编号
操作符类成员 | 对象 |
---|---|
支持过程 1 | internal function brin_bloom_opcinfo() |
支持过程 2 | internal function brin_bloom_add_value() |
支持过程 3 | internal function brin_bloom_consistent() |
支持过程 4 | internal function brin_bloom_union() |
支持过程 11 | function to compute hash of an element |
操作符策略 1 | operator equal-to |
支持过程编号1-10是为BRIN内部函数保留的,因此SQL级别的函数从编号11开始。 支持函数编号11是构建索引所需要的主函数。 它可以接受一个与操作符类具有相同数据类型的参数,并返回值的hash。
minmax-multi操作符类也适用于实现完全有序集的数据类型,也可以看作是minmax操作符类的简单扩展。 minmax操作符类汇总值,从每个块范围到单个连续的间隔中,而minmax-multi则允许将值汇总到多个更小的间隔中,以提升离群值的处理。 可以将minmax-multi支持过程与相应的操作符一起使用,如表 68.5中所示。 所有操作符类成员(过程和操作符)都是强制性的。
表 68.5. minmax-multi操作符类的过程和支持编号
操作符类成员 | 对象 |
---|---|
支持过程 1 | 内部函数 brin_minmax_multi_opcinfo() |
支持过程 2 | 内部函数 brin_minmax_multi_add_value() |
支持过程 3 | 内部函数 brin_minmax_multi_consistent() |
支持过程 4 | 内部函数 brin_minmax_multi_union() |
支持过程 11 | function to compute distance between two values (length of a range) |
操作符策略 1 | operator less-than |
操作符策略 2 | operator less-than-or-equal-to |
操作符策略 3 | operator equal-to |
操作符策略 4 | operator greater-than-or-equal-to |
操作符策略 5 | operator greater-than |
minmax 和 inclusion 操作符类都支持跨数据类型操作符,不过如果要支持
会让依赖性变得更加复杂。minmax 操作符类要求用具有同样数据类型的
参数来定义一个完全的操作符集合。它允许通过定义额外的操作符集合来
支持附加的数据类型。如
表 68.3中所示,
inclusion 操作符类的操作符策略是依赖于另一种操作符策略的(或者和它们
自身相同的操作符策略)。它们要求定义依赖性操作符时,把
STORAGE
数据类型作为左手边参数并且让其他支持的数据类型
作为右手边的参数。minmax 的例子可见
float4_minmax_ops
,inclusion 的例子是
box_inclusion_ops
。