如 表 38.3 所示,btree 运算符类必须提供五个比较运算符,<
、<=
、=
、>=
和 >
。人们可能会认为 <>
也应该是运算符类的一部分,但事实并非如此,因为在索引搜索中使用 <>
WHERE 子句几乎永远不会有用。(出于某些目的,计划程序将 <>
视为与 btree 运算符类相关联;但它通过 =
运算符的否定链接找到该运算符,而不是从 pg_amop
中找到。)
当多个数据类型共享近乎相同的排序语义时,它们的运算符类可以分组到一个运算符族中。这样做是有利的,因为它允许计划程序对跨类型比较进行推断。族中的每个运算符类都应包含其输入数据类型的单类型运算符(以及关联的支持函数),而跨类型比较运算符和支持函数在族中是“松散”的。建议在族中包含一组完整的跨类型运算符,从而确保计划程序可以表示它从传递性中推断出的任何比较条件。
btree 运算符族必须满足一些基本假设
一个 =
运算符必须是一个等价关系;也就是说,对于数据类型的所有非空值 A
、B
、C
A
=
A
为真(自反律)
如果 A
=
B
,则 B
=
A
(对称律)
如果 A
=
B
且 B
=
C
,则 A
=
C
(传递律)
一个 <
运算符必须是一个强序关系;也就是说,对于所有非空值 A
、B
、C
A
<
A
为假(非自反律)
如果 A
<
B
且 B
<
C
,则 A
<
C
(传递律)
此外,排序是完全的;也就是说,对于所有非空值 A
、B
恰好有 A
<
B
、A
=
B
和 B
<
A
中的一个为真(三段论律)
(当然,三段论律证明了比较支持函数的定义。)
其他三个运算符显然是根据 =
和 <
定义的,并且必须与它们保持一致。
对于支持多种数据类型的运算符族,当A
、B
、C
取自族中的任何数据类型时,上述定律必须成立。传递定律是最难确保的,因为在跨类型情况下,它们表示两个或三个不同运算符的行为是一致的。例如,将float8
和numeric
放入同一个运算符族中是行不通的,至少在当前语义下,numeric
值会被转换为float8
以与float8
进行比较。由于float8
的精度有限,这意味着有不同的numeric
值将与同一个float8
值相等,因此传递定律将失败。
多数据类型族的另一个要求是,在运算符族中包含的数据类型之间定义的任何隐式或二进制强制转换都不能改变关联的排序顺序。
btree 索引需要在单个数据类型中保持这些定律的原因应该很清楚:如果没有这些定律,就没有顺序来排列键。此外,使用不同数据类型的比较键进行索引搜索需要比较在两种数据类型之间合理地进行。btree 索引机制本身并不严格要求扩展到族中的三个或更多数据类型,但计划程序出于优化目的依赖于它们。