Postgresql 中文操作指南
67.3. B-Tree Support Functions #
如 Table 38.9所示,btree 定义了一个必选支持函数和四个可选支持函数。这五个用户定义的方法是:
-
order
-
对于 b-tree 运算符族为其提供比较运算符的每一种数据类型组合,它必须提供注册在 pg_amproc 中的比较支持函数,其中支持函数号为 1,而 amproclefttype / amprocrighttype 等于比较的左右数据类型(即,匹配运算符在 pg_amop 中注册的相同数据类型)。比较函数必须采用两个非空值 A 和 B ,并返回一个 int32 值,当 A < B 、 A = B 或 A > B 时,该值分别为 < 0 、 0 或 > 0 。不允许空结果:数据类型的所有值都必须可比较。请参阅 src/backend/access/nbtree/nbtcompare.c 了解示例。
-
如果要比较的值为可排序数据类型,则使用标准 PG_GET_COLLATION() 机制将合适的比较规则 OID 传递给比较支持函数。
-
-
sortsupport
-
此外,btree 运算符族还可以提供 sort support 函数,在支持函数号码 2 下注册。这些函数允许以比简单调用比较支持函数更高效的方式实现比较以进行排序。在此过程中所涉及的 API 在 src/include/utils/sortsupport.h 中定义。
-
-
in_range
-
b-tree 运算符族可能会提供注册在支持函数号 3 下的 in_range 支持函数(可选)。这些函数不会在 b-tree 索引操作期间使用;相反,它们扩展了运算符族的语义,使其能够支持包含 RANGE offset PRECEDING 和 RANGE offset FOLLOWING 帧边界类型的窗口子句(请参阅 Section 4.2.8 )。从根本上说,提供的信息是按与族的数据排序兼容的方式添加或减去 offset 值的方式。
-
in_range 函数必须具有以下签名
-
in_range(val type1, base type1, offset type2, sub bool, less bool)
returns bool
-
val 和 base 的类型必须相同,该类型是运算符族支持的类型之一(即它为此提供排序的类型)。但是,offset 的类型可能不同,可能为该族原本不支持的类型。一个示例是内置的 time_ops 族提供了一个 in_range 函数,其 offset 的类型为 interval。族可以为其任何支持的类型提供 in_range 函数,还可以为一个或多个 offset 类型提供该函数。每个 in_range 函数都应在 pg_amproc 中输入,其中 amproclefttype 等于 type1,amprocrighttype 等于 type2。
-
in_range 函数的基本语义取决于两个布尔标志参数。它应该添加或减去 base 和 offset,然后将 val 与结果进行比较,如下所示:
-
在执行此操作之前,函数应检查 offset 的符号:如果它小于零,则引发错误 ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE (22013),并显示“窗口函数中前导或后续大小无效”之类的错误文本。(SQL 标准要求这样做,尽管非标准运算符族可以忽略此限制,因为似乎很少有语义需要这样做。)此要求已委托给 in_range 函数,以便核心代码无需理解对特定数据类型来说“小于零”是什么意思。
-
还有个额外的期望: in_range 函数如果实际可行,应避免在 base + offset 或 base - offset 溢出时引发错误。即使该值超出数据类型范围,也可以确定正确的比较结果。请注意,如果数据类型包括“无穷大”或“NaN”之类的概念,则可能需要格外小心,以确保 in_range 的结果与运算符族的常规排序方式一致。
-
in_range 函数的结果必须与运算符族施加的排序顺序保持一致。准确来说,给定 offset 和 sub 的任何固定值,则:
-
当 less = false 时,具有反向条件的类似语句成立。
-
如果要排序的类型 (type1) 可归类,则会使用标准 PG_GET_COLLATION() 机制将适当的归类 OID 传递给 in_range 函数。
-
in_range 函数不需要处理 NULL 输入,通常会被标记为严格。
-
equalimage
-
-
可选地,btree 运算符系列可以提供 equalimage(“相等隐含图像相等”)支持函数,以支持函数编号 4 注册。这些函数允许核心代码确定在何时可以安全应用 btree 去重优化。目前,只有在构建或重建索引时才会调用 equalimage 函数。
-
equalimage 函数必须具有以下签名:
equalimage(opcintype oid) returns bool
-
返回值是关于运算符类和归类的静态信息。返回 true 表明运算符类的 order 函数保证仅在 A 和 B 参数同样可以互换而没有任何语义信息损失时,才会返回 0(“参数相等”)。不注册 equalimage 函数或返回 false 表明无法假设此条件成立。
-
opcintype 参数是运算符类索引的数据类型的 pg_type 。oid_。这是一种便利,允许在运算符类中重复使用相同的底层 equalimage 函数。如果 opcintype_ 是可整理数据类型,则使用标准 PG_GET_COLLATION() 机制将相应的整理 OID 传递给 equalimage 函数。
-
就运算符类而言,返回 true 表明去重是安全的(或对其 equalimage 函数传递了 OID 的归类是安全的)。但是,只有当 every 索引列使用注册了 equalimage 函数的运算符类,并且每个函数在调用后实际返回 true 时,核心代码才会认为某个索引的去重是安全的。
-
图像相等与简单的按位相等是 almost 同样的条件。有一个细微区别:在索引 varlena 数据类型时,两个图像相等数据项的磁盘表示可能由于输入中 TOAST 压缩的不一致应用,而不能按位相等。正式地说,当运算符类的 equalimage 函数返回 true 时,可以安全地假设 datum_image_eq() C 函数总是与运算符类的 order 函数一致(只要将相同的整理 OID 传递给了 equalimage 和 order 函数)。
-
核心代码根本无法基于同一系列中其他运算符类的详细信息推断出多数据类型的系列中运算符类的“相等隐含图像相等”状态。此外,运算符族注册跨类型 equalimage 函数没有道理,并且尝试这样做会导致错误。这是因为“相等隐含图像相等”状态不仅取决于排序/相等语义,而这些语义或多或少在运算符族级别上定义。通常,必须单独考虑特定数据类型实施的语义。
-
PostgreSQL 发行版中包含的运算符类遵循的惯例是注册一个库存、通用 equalimage 函数。大多数运算符类注册 btequalimage(),这表明去重是无条件安全的。可归类数据类型的运算符类,例如 text 注册 btvarstrequalimage(),这表明在确定性归类下进行去重是安全的。第三方扩展的最佳做法是注册自己的自定义函数以保留控制权。
-
options
-
-
可选地,B 树运算符族可以提供 options(“运算符类特定选项”)支持函数,以支持函数编号 5 注册。这些函数定义了一组用户可见的参数,用于控制运算符类的行为。
-
options 支持函数必须具有以下签名:
options(relopts local_relopts *) returns void
-
该函数会传递到 local_relopts 结构的指针,需要使用一组运算符类特定选项来填充该指针。可以使用 PG_HAS_OPCLASS_OPTIONS() 和 PG_GET_OPCLASS_OPTIONS() 宏从其他支持函数访问这些选项。
-
目前,没有 B 树运算符类具有 options 支持函数。与 GiST、SP-GiST、GIN 和 BRIN 不同,B 树不允许灵活表示键。因此, options 在当前 B 树索引访问方法中可能应用不多。尽管如此,此支持函数已添加到 B 树中以实现统一,并且可能会在 PostgreSQL 的 B 树进一步演变期间找到用途。