# 38.16.索引接口扩展

38.16.1. 索引方法和运算符类

38.16.2. 指数法策略

38.16.3. 索引方法支持例程

38.16.4. 一个例子

38.16.5. 算子类和算子族

38.16.6. 系统对运算符类的依赖性

38.16.7. 排序运算符

38.16.8. 算子类的特殊性质

到目前为止描述的过程允许您定义新类型、新函数和新运算符。然而,我们还不能在新数据类型的列上定义索引。要做到这一点,我们必须定义操作员类对于新的数据类型。在本节后面,我们将用一个例子来说明这个概念:B树索引方法的一个新操作符类,它以升序绝对值顺序存储和排序复数。

运算符类可以分为操作员家庭显示语义兼容类之间的关系。当只涉及一种数据类型时,一个操作符类就足够了,所以我们将首先关注这种情况,然后返回操作符族。

# 38.16.1.索引方法和运算符类

这个普甘表中每个索引方法(内部称为访问方法)包含一行。PostgreSQL内置了对定期访问表的支持,但所有索引方法都在普甘。通过编写必要的代码,然后在中创建条目,可以添加新的索引访问方法普甘-但这超出了本章的范围(参见第62章).

索引方法的例程并不直接知道索引方法将操作的数据类型。相反,一个操作员类标识索引方法在处理特定数据类型时需要使用的操作集。运算符类之所以被称为运算符类,是因为它们指定的一件事是哪里-可与索引一起使用的子句运算符(即,可转换为索引扫描限定)。操作符类还可以指定一些支持功能索引方法的内部操作所需的,但不直接对应于任何哪里-可与索引一起使用的子句运算符。

可以为同一数据类型和索引方法定义多个运算符类。通过这样做,可以为单个数据类型定义多组索引语义。例如,B树索引要求为其处理的每种数据类型定义排序顺序。对于复数数据类型,一个B-树运算符类可以按复数绝对值对数据进行排序,另一个B-树运算符类可以按实部排序,依此类推。通常,其中一个运算符类将被视为最常用的运算符类,并将被标记为该数据类型和索引方法的默认运算符类。

相同的运算符类名可用于几种不同的索引方法(例如,B树和哈希索引方法都有名为国际4_行动),但每一类都是独立的实体,必须单独定义。

# 38.16.2.指数法策略

与运算符类关联的运算符由“策略号”标识,用于在其运算符类的上下文中标识每个运算符的语义。例如,B-树对键进行严格的排序,从小到大,因此“小于”和“大于或等于”等运算符对于B-树来说很有趣。因为PostgreSQL允许用户定义运算符,所以PostgreSQL不能查看运算符的名称(例如。,<>=)告诉我这是什么样的比较。相反,索引方法定义了一组“策略”,可以将其视为广义运算符。每个操作符类指定哪个实际操作符对应于特定数据类型的每个策略以及索引语义的解释。

B树索引方法定义了五种策略,如表38.3.

表38.3.B-树策略

活动 战略编号
少于 1.
小于或等于 2.
相同的 3.
大于或等于 4.
大于 5.

哈希索引只支持相等比较,因此它们只使用一种策略,如中所示表38.4.

表38.4.散列策略

活动 战略编号
相同的 1.

GiST索引更灵活:它们根本没有一套固定的策略。相反,每个特定GiST运算符类的“一致性”支持例程会以自己喜欢的方式解释策略编号。例如,几个内置的GiST索引操作符类对二维几何对象进行索引,提供了中所示的“R树”策略表38.5其中四个是真实的二维测试(重叠、相同、包含、包含);四的人只考虑X方向;另外四个在Y方向提供相同的测试。

表38.5.GiST二维“R-树”策略

活动 战略编号
完全离开 1.
不延伸到权利 2.
重叠 3.
不延伸到左侧 4.
绝对的权利 5.
相同的 6.
包含 7.
包含在 8.
不延伸到上面 9
严格低于 10
严格高于 11
不延伸到下面 12

SP GiST索引在灵活性方面与GiST索引类似:它们没有固定的策略集。相反,每个操作符类的支持例程根据操作符类的定义解释策略编号。例如,内置运算符类用于点的策略编号如所示表38.6.

表38.6.SP要点策略

活动 战略编号
完全离开 1.
绝对的权利 5.
相同的 6.
包含在 8.
严格低于 10
严格高于 11

GIN索引与GiST和SP GiST索引类似,因为它们也没有固定的策略集。相反,每个操作符类的支持例程根据操作符类的定义解释策略编号。例如,内置运算符类用于数组的策略编号如所示表38.7.

表38.7.杜松子酒阵列策略

活动 战略编号
重叠 1.
包含 2.
包含在 3.
相同的 4.

BRIN索引与GiST、SP GiST和GIN索引相似,因为它们也没有固定的策略集。相反,每个操作符类的支持例程根据操作符类的定义解释策略编号。例如,内置服务器使用的策略编号极小化极大运算符类如中所示表38.8.

表38.8.布林极小值策略

活动 战略编号
少于 1.
小于或等于 2.
相同的 3.
大于或等于 4.
大于 5.

请注意,上面列出的所有运算符都返回布尔值。实际上,所有定义为索引方法搜索运算符的运算符都必须返回类型布尔值,因为它们必须出现在哪里子句与索引一起使用。(一些索引访问方法也支持排序运算符,通常不返回布尔值;该功能将在中讨论第38.16.7节.)

# 38.16.3.索引方法支持例程

策略通常不足以让系统了解如何使用索引。实际上,索引方法需要额外的支持例程才能工作。例如,B树索引方法必须能够比较两个键,并确定其中一个键是大于、等于还是小于另一个键。类似地,哈希索引方法必须能够计算键值的哈希代码。这些操作与SQL命令中限定使用的运算符不对应;它们是索引方法在内部使用的管理例程。

与策略一样,operator类确定对于给定的数据类型和语义解释,哪些特定函数应该扮演这些角色。index方法定义了它所需的函数集,operator类通过将它们分配给index方法指定的“支持函数号”来识别要使用的正确函数。

此外,一些OPClass允许用户指定控制其行为的参数。每个内置索引访问方法都有一个可选的选项支持函数,它定义了一组特定于opclass的参数。

B-树需要一个比较支持函数,并允许操作员类作者选择提供四个额外的支持函数,如中所示表38.9。这些支持功能的要求将在中进一步解释第64.3节.

表38.9.B树支持函数

作用 支持号码
比较两个键并返回一个小于零、零或大于零的整数,指示第一个键是小于、等于还是大于第二个键 1.
返回C可调用排序支持函数的地址(可选) 2.
将测试值与基础值加/减偏移量进行比较,并根据比较结果返回true或false(可选) 3.
确定使用operator类应用btree重复数据消除优化的索引是否安全(可选) 4.
定义特定于此运算符类的选项(可选) 5.

散列索引需要一个支持函数,并允许操作员类作者选择提供另外两个支持函数,如中所示表38.10.

表38.10.散列支持函数

作用 支持号码
计算密钥的32位哈希值 1.
计算给定64位salt的密钥的64位哈希值;如果salt为0,则结果的低32位必须与函数1计算的值相匹配(可选) 2.
定义特定于此运算符类的选项(可选) 3.

GiST索引有11个支持函数,其中6个是可选的,如中所示表38.11(有关更多信息,请参阅第65章.)

表38.11.GiST支持功能

作用 描述 支持号码
一致的 确定键是否满足查询限定符 1.
协会 计算一组键的并集 2.
压紧 计算要索引的键或值的压缩表示(可选) 3.
减压 计算压缩密钥的解压缩表示(可选) 4.
处罚 计算使用给定子树键向子树插入新键的惩罚 5.
皮克斯普利特 确定要将页面的哪些条目移动到新页面,并计算结果页面的联合键 6.
相同的 比较两个键,如果它们相等,则返回true 7.
距离 确定从键到查询值的距离(可选) 8.
取来 为仅索引扫描计算压缩键的原始表示形式(可选) 9
选项 定义特定于此运算符类的选项(可选) 10
sortsupport 提供用于快速索引构建的排序比较器(可选) 11

SP GiST索引有六个支持函数,其中一个是可选的,如中所示表38.12(有关更多信息,请参阅第66章.)

表38.12.SP GiST支持功能

作用 描述 支持号码
配置 提供有关运算符类的基本信息 1.
选择 确定如何将新值插入内部元组 2.
皮克斯普利特 确定如何划分一组值 3.
内部一致 确定查询需要搜索哪些子分区 4.
叶_一致 确定键是否满足查询限定符 5.
选项 定义特定于此运算符类的选项(可选) 6.

GIN索引有七个支持函数,其中四个是可选的,如中所示表38.13(有关更多信息,请参阅第67章.)

表38.13.GIN支持功能

作用 描述 支持号码
比较 比较两个键并返回一个小于零、零或大于零的整数,指示第一个键是小于、等于还是大于第二个键 1.
提取值 从要索引的值中提取键 2.
提取查询 从查询条件中提取密钥 3.
一致的 确定值是否匹配查询条件(布尔变量)(如果支持函数6存在,则可选) 4.
比较部分 比较查询中的部分键和索引中的键,并返回小于零、零或大于零的整数,指示GIN是否应忽略此索引项、将该项视为匹配项或停止索引扫描(可选) 5.
矛盾一致 确定值是否匹配查询条件(三元变量)(如果支持函数4存在,则可选) 6.
选项 定义特定于此运算符类的选项(可选) 7.

BRIN索引有五个基本支持函数,其中一个是可选的,如中所示表38.14.某些版本的基本功能需要提供额外的支持功能。(有关更多信息,请参见第68.3节.)

表38.14.BRIN支持功能

作用 描述 支持号码
opcInfo 返回描述索引列摘要数据的内部信息 1.
增值 向现有摘要索引元组添加新值 2.
一致的 确定值是否与查询条件匹配 3.
协会 计算两个摘要元组的并集 4.
选项 定义特定于此运算符类的选项(可选) 5.

与搜索运算符不同,支持函数返回特定索引方法所需的任何数据类型;例如,在B-树的比较函数中,一个有符号整数。每个支持函数的参数数量和类型同样取决于索引方法。对于B-树和散列,比较和散列支持函数采用与运算符类中包含的运算符相同的输入数据类型,但大多数GiST、SP GiST、GIN和BRIN支持函数并非如此。

# 38.16.4.一个例子

现在我们已经看到了这些想法,下面是一个创建新操作符类的示例。(您可以在中找到此示例的工作副本。)src/tutorial/complex。Csrc/tutorial/complex。sql在源代码分发中。)operator类封装了按绝对值顺序对复数排序的运算符,因此我们选择名称复杂的abs操作.首先,我们需要一组操作员。中讨论了定义运算符的过程第38.14节.对于B-树上的运算符类,我们需要的运算符是:

  • 绝对值小于(策略1)

  • 绝对值小于或等于(策略2)

  • 绝对值相等(策略3)

  • 绝对值大于或等于(策略4)

  • 绝对值大于(策略5)

    定义一组相关的比较运算符时,最不容易出错的方法是先编写B树比较支持函数,然后将其他函数作为支持函数的单行包装器编写。这降低了角落案例得到不一致结果的可能性。按照这种方法,我们首先写:

#define Mag(c)  ((c)->x*(c)->x + (c)->y*(c)->y)

static int
complex_abs_cmp_internal(Complex *a, Complex *b)
{
    double      amag = Mag(a),
                bmag = Mag(b);

    if (amag < bmag)
        return -1;
    if (amag > bmag)
        return 1;
    return 0;
}

现在,小于函数如下所示:

PG_FUNCTION_INFO_V1(complex_abs_lt);

Datum
complex_abs_lt(PG_FUNCTION_ARGS)
{
    Complex    *a = (Complex *) PG_GETARG_POINTER(0);
    Complex    *b = (Complex *) PG_GETARG_POINTER(1);

    PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0);
}

其他四个函数的不同之处在于它们如何将内部函数的结果与零进行比较。

接下来,我们将根据函数向SQL声明函数和运算符:

CREATE FUNCTION complex_abs_lt(complex, complex) RETURNS bool
    AS 'filename', 'complex_abs_lt'
    LANGUAGE C IMMUTABLE STRICT;

CREATE OPERATOR < (
   leftarg = complex, rightarg = complex, procedure = complex_abs_lt,
   commutator = > , negator = >= ,
   restrict = scalarltsel, join = scalarltjoinsel
);

重要的是指定正确的换向器和求反器运算符,以及适当的限制和连接选择性函数,否则优化器将无法有效利用索引。

这里还有其他值得注意的事情:

  • 只能有一个名为,=还有打字复杂的对于两个操作数。在这种情况下,我们没有其他操作员=对于复杂的,但如果我们正在构建一种实用的数据类型,我们可能会希望=是复数的普通相等运算(而不是绝对值相等)。在这种情况下,我们需要使用其他运算符名称来复杂的_abs _eq.

  • 尽管PostgreSQL可以处理具有相同SQL名称的函数,只要它们具有不同的参数数据类型,但C只能处理具有给定名称的一个全局函数。所以我们不应该把C函数简单地命名为abs_eq.通常,在C函数名中包含数据类型名是一种好的做法,以免与其他数据类型的函数冲突。

  • 我们可以用SQL来命名函数abs_eq,依靠PostgreSQL通过参数数据类型将其与任何其他同名SQL函数区分开来。为了保持示例的简单性,我们使函数在C级和SQL级具有相同的名称。

    下一步是注册B树所需的支持例程。实现此功能的示例C代码位于包含运算符函数的同一文件中。下面是我们声明函数的方式:

CREATE FUNCTION complex_abs_cmp(complex, complex)
    RETURNS integer
    AS 'filename'
    LANGUAGE C IMMUTABLE STRICT;

现在我们有了所需的操作符和支持例程,我们终于可以创建操作符类了:

CREATE OPERATOR CLASS complex_abs_ops
    DEFAULT FOR TYPE complex USING btree AS
        OPERATOR        1       < ,
        OPERATOR        2       <= ,
        OPERATOR        3       = ,
        OPERATOR        4       >= ,
        OPERATOR        5       > ,
        FUNCTION        1       complex_abs_cmp(complex, complex);

我们完了!现在应该可以在上创建和使用B树索引了复杂的柱。

我们可以更详细地编写运算符条目,如:

        OPERATOR        1       < (complex, complex) ,

但是,当操作符采用我们为其定义操作符类的相同数据类型时,不需要这样做。

上面的示例假设您希望使这个新的操作符类成为复杂的数据类型。如果你不知道,就省去这个词违约.

# 38.16.5.算子类和算子族

到目前为止,我们已经隐式地假设一个操作符类只处理一种数据类型。虽然在特定的索引列中肯定只能有一种数据类型,但将索引列与不同数据类型的值进行比较的索引操作通常很有用。此外,如果一个跨数据类型运算符与一个运算符类结合使用,通常情况下,另一个数据类型有自己的相关运算符类。明确相关类之间的连接很有帮助,因为这有助于规划器优化SQL查询(尤其是对于B树运算符类,因为规划器包含大量关于如何使用它们的知识)。

为了满足这些需求,PostgreSQL使用了操作员家庭.一个运算符族包含一个或多个运算符类,还可以包含可转位运算符和相应的支持函数,这些运算符和函数作为一个整体属于该族,但不属于该族中的任何单个类。我们说,这样的运算符和函数在族中是“松散的”,而不是绑定到特定的类中。通常,每个运算符类都包含单个数据类型运算符,而跨数据类型运算符在族中是松散的。

运算符族中的所有运算符和函数都必须具有兼容的语义,其中兼容性要求由索引方法设置。因此,您可能想知道,为什么要费心将该族的特定子集单独作为运算符类;事实上,从很多方面来看,阶级划分是无关紧要的,家庭是唯一有趣的群体。定义运算符类的原因是,它们指定了支持任何特定索引所需的族的数量。如果存在使用运算符类的索引,则在不删除该索引的情况下无法删除该运算符类,但可以删除运算符族的其他部分,即其他运算符类和松散运算符。因此,应该指定一个操作符类,以包含使用特定数据类型的索引合理需要的最小操作符和函数集,然后可以将相关但非必要的操作符添加为操作符族的松散成员。

例如,PostgreSQL有一个内置的B树运算符族整数运算,其中包括运算符类国际行动, 国际4_行动国际行动有关上的索引比基特 (int8), 整数 (int4),及短整型 (国际标准2)各列。族还包含允许比较这两种类型中的任意两个的跨数据类型比较操作符,以便可以使用另一种类型的比较值搜索其中一种类型上的索引。可以通过以下定义复制族:

CREATE OPERATOR FAMILY integer_ops USING btree;

CREATE OPERATOR CLASS int8_ops
DEFAULT FOR TYPE int8 USING btree FAMILY integer_ops AS
  -- standard int8 comparisons
  OPERATOR 1 < ,
  OPERATOR 2 <= ,
  OPERATOR 3 = ,
  OPERATOR 4 >= ,
  OPERATOR 5 > ,
  FUNCTION 1 btint8cmp(int8, int8) ,
  FUNCTION 2 btint8sortsupport(internal) ,
  FUNCTION 3 in_range(int8, int8, int8, boolean, boolean) ,
  FUNCTION 4 btequalimage(oid) ;

CREATE OPERATOR CLASS int4_ops
DEFAULT FOR TYPE int4 USING btree FAMILY integer_ops AS
  -- standard int4 comparisons
  OPERATOR 1 < ,
  OPERATOR 2 <= ,
  OPERATOR 3 = ,
  OPERATOR 4 >= ,
  OPERATOR 5 > ,
  FUNCTION 1 btint4cmp(int4, int4) ,
  FUNCTION 2 btint4sortsupport(internal) ,
  FUNCTION 3 in_range(int4, int4, int4, boolean, boolean) ,
  FUNCTION 4 btequalimage(oid) ;

CREATE OPERATOR CLASS int2_ops
DEFAULT FOR TYPE int2 USING btree FAMILY integer_ops AS
  -- standard int2 comparisons
  OPERATOR 1 < ,
  OPERATOR 2 <= ,
  OPERATOR 3 = ,
  OPERATOR 4 >= ,
  OPERATOR 5 > ,
  FUNCTION 1 btint2cmp(int2, int2) ,
  FUNCTION 2 btint2sortsupport(internal) ,
  FUNCTION 3 in_range(int2, int2, int2, boolean, boolean) ,
  FUNCTION 4 btequalimage(oid) ;

ALTER OPERATOR FAMILY integer_ops USING btree ADD
  -- cross-type comparisons int8 vs int2
  OPERATOR 1 < (int8, int2) ,
  OPERATOR 2 <= (int8, int2) ,
  OPERATOR 3 = (int8, int2) ,
  OPERATOR 4 >= (int8, int2) ,
  OPERATOR 5 > (int8, int2) ,
  FUNCTION 1 btint82cmp(int8, int2) ,

  -- cross-type comparisons int8 vs int4
  OPERATOR 1 < (int8, int4) ,
  OPERATOR 2 <= (int8, int4) ,
  OPERATOR 3 = (int8, int4) ,
  OPERATOR 4 >= (int8, int4) ,
  OPERATOR 5 > (int8, int4) ,
  FUNCTION 1 btint84cmp(int8, int4) ,

  -- cross-type comparisons int4 vs int2
  OPERATOR 1 < (int4, int2) ,
  OPERATOR 2 <= (int4, int2) ,
  OPERATOR 3 = (int4, int2) ,
  OPERATOR 4 >= (int4, int2) ,
  OPERATOR 5 > (int4, int2) ,
  FUNCTION 1 btint42cmp(int4, int2) ,

  -- cross-type comparisons int4 vs int8
  OPERATOR 1 < (int4, int8) ,
  OPERATOR 2 <= (int4, int8) ,
  OPERATOR 3 = (int4, int8) ,
  OPERATOR 4 >= (int4, int8) ,
  OPERATOR 5 > (int4, int8) ,
  FUNCTION 1 btint48cmp(int4, int8) ,

  -- cross-type comparisons int2 vs int8
  OPERATOR 1 < (int2, int8) ,
  OPERATOR 2 <= (int2, int8) ,
  OPERATOR 3 = (int2, int8) ,
  OPERATOR 4 >= (int2, int8) ,
  OPERATOR 5 > (int2, int8) ,
  FUNCTION 1 btint28cmp(int2, int8) ,

  -- cross-type comparisons int2 vs int4
  OPERATOR 1 < (int2, int4) ,
  OPERATOR 2 <= (int2, int4) ,
  OPERATOR 3 = (int2, int4) ,
  OPERATOR 4 >= (int2, int4) ,
  OPERATOR 5 > (int2, int4) ,
  FUNCTION 1 btint24cmp(int2, int4) ,

  -- cross-type in_range functions
  FUNCTION 3 in_range(int4, int4, int8, boolean, boolean) ,
  FUNCTION 3 in_range(int4, int4, int2, boolean, boolean) ,
  FUNCTION 3 in_range(int2, int2, int8, boolean, boolean) ,
  FUNCTION 3 in_range(int2, int2, int4, boolean, boolean) ;

注意,这个定义“重载”操作符策略和支持函数号:每个数字在族中多次发生。只要特定数字的每个实例都有不同的输入数据类型,就允许这样做。两个输入类型都等于运算符类的输入类型的实例是该运算符类的主运算符和支持函数,在大多数情况下,应声明为运算符类的一部分,而不是作为族的松散成员。

在B树操作符族中,族中的所有操作符必须进行兼容排序,如中详细说明第64.2节. 对于族中的每个操作符,必须有一个支持函数,其输入数据类型与操作员相同。建议完整的族,即,对于数据类型的每一个组合,都包含所有操作符。每个操作符类应该只包含非交叉类型操作符和其数据类型的支持函数。

要构建多数据类型哈希运算符族,必须为族支持的每个数据类型创建兼容的哈希支持函数。这里的兼容性意味着,函数保证返回相同的哈希代码,对于任何两个值,这些值被族的等式操作符视为相等,即使值是不同类型的。当类型具有不同的物理表示时,通常很难完成这一点,但在某些情况下可以做到。此外,将运算符族中表示的一个数据类型的值转换为也通过隐式或二进制强制转换在操作符族中表示的另一数据类型,不得更改计算的哈希值。注意,每个数据类型只有一个支持函数,而不是每个相等运算符中的一个。建议完整族,即为数据类型的每一组合提供一个相等运算符。每个操作符类应该只包含非交叉类型相等运算符及其数据类型的支持函数。

GiST、SP GiST和GIN索引没有任何交叉数据类型操作的明确概念。支持的运算符集就是给定操作符类的主要支持函数可以处理的任何一个。

在BRIN中,需求取决于提供操作符类的框架。对于基于极小极大,所需的行为与B树操作符族相同:族中的所有操作符必须兼容排序,并且强制转换不得更改关联的排序顺序。

#

在PostgreSQL 8.3之前,没有运算符族的概念,因此任何打算与索引一起使用的跨数据类型运算符都必须直接绑定到索引的运算符类中。虽然这种方法仍然有效,但不推荐使用它,因为它使索引的依赖关系过于广泛,而且当两种数据类型的运算符位于同一个运算符族中时,规划器可以更有效地处理跨数据类型的比较。

# 38.16.6.系统对运算符类的依赖性

PostgreSQL使用运算符类来推断运算符的属性,其方式不仅限于运算符是否可以与索引一起使用。因此,即使无意为数据类型的任何列编制索引,也可能需要创建运算符类。

特别是SQL特性,例如订购人不同的这需要对值进行比较和排序。为了在用户定义的数据类型上实现这些功能,PostgreSQL会为该数据类型查找默认的B树运算符类。这个操作符类的“equals”成员定义了系统的值相等的概念分组不同的,运算符类施加的排序顺序定义了默认值订购人点餐。

如果数据类型没有默认的B树运算符类,系统将查找默认的哈希运算符类。但是,由于这种运算符类只提供相等性,所以它只能支持分组而不是排序。

当数据类型没有默认的运算符类时,如果试图将这些SQL功能用于该数据类型,则会出现“无法识别排序运算符”之类的错误。

# 笔记

在7.4之前的PostgreSQL版本中,排序和分组操作将隐式使用名为=, <>.依赖默认运算符类的新行为避免了对具有特定名称的运算符的行为进行任何假设。

通过在a中指定类的小于运算符,可以按非默认B树运算符类进行排序使用例如,选项

SELECT * FROM mytable ORDER BY somecol USING ~<~;

或者,在中指定类的大于运算符使用选择降序排序。

用户定义类型的数组的比较还依赖于该类型的默认B树运算符类定义的语义。如果没有默认的B树运算符类,但有默认的哈希运算符类,则支持数组相等,但不支持排序比较。

另一个需要更多数据类型特定知识的SQL特性是范围 抵消 之前的/下列的窗口功能的框架选项(请参见第4.2.8节).对于以下查询:

SELECT sum(x) OVER (ORDER BY x RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING)
  FROM mytable;

仅仅知道如何按订单是不够的十、; 数据库还必须了解如何对当前行的十、以标识当前窗口框架的边界。将结果边界与其他行的十、可以使用定义订购人排序——但是加法和减法运算符不是运算符类的一部分,那么应该使用哪些运算符呢?硬连接这种选择是不可取的,因为不同的排序顺序(不同的B树运算符类)可能需要不同的行为。因此,B-树运算符类可以指定在里面_范围支持函数,它封装了对排序顺序有意义的加减行为。它甚至可以提供一个以上的_范围支持功能,以防有多个数据类型可以用作范围条款。如果与窗口的订购人子句中没有匹配项_射程支持功能范围 抵消 之前的/下列的选项不受支持。

另一个重要的一点是,出现在哈希运算符族中的相等运算符是哈希联接、哈希聚合和相关优化的候选运算符。散列运算符族在这里很重要,因为它标识要使用的散列函数。

# 38.16.7.排序运算符

一些索引访问方法(目前只有GiST和SP GiST)支持排序运算符.到目前为止我们一直在讨论的是搜索操作员.搜索运算符是可以搜索索引以查找所有符合条件的行的运算符哪里 索引列 操作人员 常数。请注意,没有承诺返回匹配行的顺序。相反,排序运算符不限制可以返回的行集,而是确定它们的顺序。排序运算符是一种可以扫描索引的运算符,以便按照订购人 索引列 操作人员 常数。这样定义排序运算符的原因是,如果运算符是测量距离的运算符,则它支持最近邻搜索。例如,像

SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;

查找距离给定目标点最近的十个位置。location列上的GiST索引可以有效地实现这一点,因为<->是一个订购操作员。

虽然搜索运算符必须返回布尔结果,但排序运算符通常会返回其他类型的结果,例如用于距离的float或numeric。此类型通常与被索引的数据类型不同。为了避免对不同数据类型的行为进行硬连接假设,需要使用排序运算符的定义来命名指定结果数据类型排序顺序的B树运算符族。正如前一节所述,B-树运算符族定义了PostgreSQL的排序概念,因此这是一种自然的表示。从那时起<->接线员返回浮动8,可以在运算符类创建命令中指定,如下所示:

OPERATOR 15    <-> (point, point) FOR ORDER BY float_ops

哪里浮球是内置的运算符族,其中包括对浮动8。此声明声明索引能够按<->操作人员

# 38.16.8.算子类的特殊性质

我们还没有讨论运算符类的两个特殊特性,主要是因为它们对最常用的索引方法没有用处。

通常,将运算符声明为运算符类(或族)的成员意味着index方法可以准确地检索满足哪里使用操作员进行条件调整。例如:

SELECT * FROM table WHERE integer_column < 4;

可以通过整型列上的B树索引完全满足。但在某些情况下,索引可以作为匹配行的不精确指南。例如,如果GiST索引只存储几何对象的边界框,那么它不能完全满足哪里测试非矩形对象(如多边形)之间重叠的条件。然而,我们可以使用索引查找其边界框与目标对象的边界框重叠的对象,然后仅对索引找到的对象进行精确的重叠测试。如果这种情况适用,则对操作员而言,该索引称为“有损”。有损索引搜索是通过让index方法返回复查标记行何时可能真正满足查询条件。然后,核心系统将在检索到的行上测试原始查询条件,以查看是否应将其作为有效匹配返回。如果索引保证返回所有需要的行,加上一些额外的行,那么这种方法是有效的,这些行可以通过执行原始的操作符调用来消除。支持有损搜索的索引方法(目前为GiST、SP GiST和GIN)允许单个操作符类的支持函数设置重新检查标志,因此这本质上是一个操作符类功能。

再考虑一下,我们只在索引中存储一个复杂对象的边界框,例如多边形。在这种情况下,将整个多边形存储在索引项中没有多大价值——我们不妨只存储一个简单的类型对象.这种情况由存储选择权创建操作符类:我们可以这样写:

CREATE OPERATOR CLASS polygon_ops
    DEFAULT FOR TYPE polygon USING gist AS
        ...
        STORAGE box;

目前,只有GiST、SP GiST、GIN和BRIN索引方法支持存储与列数据类型不同的类型。要点压紧减压支持例程必须在以下情况下处理数据类型转换:存储被使用了。SP GiST同样需要压紧支持转换为不同存储类型的功能;如果SP类也支持检索数据,则反向转换必须由一致的作用在杜松子酒里存储type标识“key”值的类型,这通常与索引列的类型不同——例如,整数数组列的运算符类可能具有仅为整数的键。杜松子酒提取值提取查询支持例程负责从索引值中提取键。布林和杜松子酒很相似存储类型标识存储的摘要值的类型,运算符类的支持过程负责正确解释摘要值。