60.3. 索引扫描

在索引扫描中,索引访问方法负责重新告知所有与* scan keys *匹配的 Tuples 的 TID。访问方法与实际从索引的父表中获取那些 Tuples,或者确定它们是否通过扫描的时间资格测试或其他条件无关。

扫描键是形式为index_key * * operator * * constant *的WHERE子句的内部表示形式,其中索引键是索引的列之一,而运算符是与之关联的运算符家族的成员之一该索引列。索引扫描具有零个或多个扫描键,这些键被隐式地进行“与”运算-返回的 Tuples 应满足所有指示的条件。

访问方法可以报告特定查询的索引为有损,或者需要重新检查。这意味着索引扫描将返回所有通过扫描键的条目,以及可能未通过扫描键的其他条目。然后,核心系统的索引扫描机制将再次将索引条件应用于堆 Tuples,以验证是否确实应该选择它。如果未指定 recheck 选项,则索引扫描必须完全返回匹配条目集。

请注意,完全取决于访问方法来确保它正确找到所有并且仅找到通过所有给定扫描键的条目。同样,核心系统将简单地交出所有与索引键和运算符系列匹配的WHERE子句,而无需进行任何语义分析来确定它们是多余还是矛盾。例如,给定WHERE x > 4 AND x > 14,其中x是 b 树索引列,则留给 b 树amrescan函数以实现第一个扫描键是冗余的并且可以丢弃。在amrescan期间所需的预处理程度将取决于索引访问方法需要将扫描键减少为“规范化”形式的程度。

有些访问方法以定义良好的 Sequences 返回索引条目,而其他访问方法则没有。访问方法可以支持排序输出的方法实际上有两种:

  • 始终以数据的自然 Sequences 返回条目的访问方法(例如 btree)应将amcanorder设置为 true。当前,此类访问方法必须将 btree 兼容策略编号用于其相等性和排序运算符。

  • 支持排序运算符的访问方法应将amcanorderbyop设置为 true。这表明索引能够以满足ORDER BY * index_key * * operator * * constant *的 Sequences 返回条目。如前所述,该形式的扫描修饰符可以传递给amrescan

amgettuple函数具有direction参数,该参数可以是ForwardScanDirection(通常情况)或BackwardScanDirection。如果amrescan之后的第一个调用指定BackwardScanDirection,那么将从后到前而不是在正常的前后方向上扫描匹配的索引条目集,因此amgettuple必须返回索引中的最后一个匹配 Tuples,而不是比通常的第一个要高。 (只有将amcanorder设置为 true 的访问方法才会发生这种情况.)首次调用后,必须准备amgettuple从最近返回的条目向任一方向推进扫描。 (但是,如果amcanbackward为 false,则所有后续调用将具有与第一个相同的方向.)

支持有序扫描的访问方法必须支持在扫描中“标记”位置,然后返回到标记位置。同一位置可能会多次还原。但是,每次扫描只需要记住一个位置。新的ammarkpos呼叫会覆盖之前标记的位置。不支持有序扫描的访问方法不必在IndexAmRoutine中提供ammarkposamrestrpos函数;将这些指针设置为 NULL。

面对索引同时插入或删除,必须始终保持扫描位置和标记位置(如果有)。如果在扫描开始时已经存在的条目没有被扫描返回,则该扫描没有返回新插入的条目,或者即使没有被扫描,扫描也可以在重新扫描或备份时返回该条目第一次回来。同样,并发删除可能会也可能不会反映在扫描结果中。重要的是,插入或删除操作不会导致扫描丢失或增加本来不是插入或删除的返回条目。

如果索引存储原始索引数据值(而不是它们的某些有损表示),则支持index-only scans很有用,其中索引返回实际数据而不仅仅是堆 Tuples 的 TID。仅当可见性图显示 TID 在全可见页面上时,才可以避免 I/O;否则必须访问堆 Tuples 以检查 MVCC 可见性。但这与访问方法无关。

代替使用amgettuple,可以使用amgetbitmap进行索引扫描,以在一次调用中获取所有 Tuples。这比amgettuple效率更高,因为它可以避免访问方法中的锁定/解锁周期。原则上amgetbitmap应该与重复的amgettuple调用具有相同的效果,但是我们施加了一些限制来简化事务。首先,amgetbitmap立即返回所有 Tuples,并且不支持标记或还原扫描位置。其次,在没有任何特定 Sequences 的位图中返回 Tuples,这就是amgetbitmap不带direction参数的原因。 (也不会为此类扫描提供 Order 运算符.)而且,由于无法返回索引 Tuples 的内容,因此也不提供使用amgetbitmap进行仅索引扫描。最后,amgetbitmap不保证对返回的 Tuples 进行任何锁定,其含义在Section 60.4中阐明。

请注意,如果访问方法的内部实现不适用于一个 API 或另一个 API,则允许该访问方法仅实现amgetbitmap而不实现amgettuple,反之亦然。