如表 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
放在同一个操作符族中是行不通的,至少在当前的语义(为了和一个float8
比较,numeric
值会被转换成float8
)下不行。因为float8
有限的精度,这意味着不同的numeric
值将被认为等于同一个float8
值,因此传递律将被破坏。
对于多数据类型操作符族的另一个要求是,其中包括的定义在数据类型之间的任何隐式或者二进制强制造型不能改变相关的排序顺序。
为何一个btree索引要求这些定律在单一数据类型中必须保持的原因应该相对比较清楚:没有这些定律就不存在用于安排键的顺序。此外,使用不同数据类型键的比较的索引搜索也要求比较操作在两种数据类型之间表现得稳定。btree索引机制本身并不严格要求在一个操作符族中扩展到三种或者更多种数据类型,但是规划器依赖于这种扩展来实现其优化的目的。