在索引扫描中,索引访问方法负责吐出它被告知的所有匹配扫描键的元组的 TID。访问方法不负责实际从索引的父表获取这些元组,也不负责确定它们是否通过了扫描的可见性测试或其他条件。
扫描键是形式为 index_key
operator
constant
的 WHERE
子句的内部表示,其中索引键是索引的列之一,而操作符是与该索引列关联的操作符族成员之一。索引扫描具有零个或多个扫描键,它们是隐式 AND 运算的——预期的返回元组将满足所有指示的条件。
访问方法可以报告某个索引对于特定查询是有损的,或者需要重新检查。这意味着索引扫描将返回所有通过扫描键的条目,可能还会附加一些不匹配的条目。核心系统的索引扫描机制然后会再次将索引条件应用于堆元组,以验证它是否确实应该被选中。如果未指定重新检查选项,则索引扫描必须返回精确匹配的条目集。
请注意,完全由访问方法负责确保它正确地找到并通过所有给定扫描键的所有条目,并且只找到这些条目。此外,核心系统只会传递与索引键和操作符族匹配的所有 WHERE
子句,而不会进行任何语义分析来确定它们是否冗余或矛盾。例如,给定 WHERE x > 4 AND x > 14
,其中 x
是一个 b-tree 索引列,需要由 b-tree 的 amrescan
函数来识别第一个扫描键是冗余的并可以被丢弃。在 amrescan
期间所需的预处理程度将取决于索引访问方法在多大程度上需要将扫描键简化为“规范化”形式。
某些访问方法按明确定义的顺序返回索引条目,而另一些则不。实际上,访问方法支持排序输出的两种不同方式。
始终按其数据的自然顺序返回条目的访问方法(例如 btree)应将 amcanorder
设置为 true。目前,此类访问方法必须为其相等和排序操作符使用与 btree 兼容的策略编号。
支持排序操作符的访问方法应将 amcanorderbyop
设置为 true。这表明索引能够按满足 ORDER BY
index_key
operator
constant
的顺序返回条目。该形式的扫描修饰符可以如前所述传递给 amrescan
。
amgettuple
函数有一个 direction
参数,它可以是 ForwardScanDirection
(正常情况)或 BackwardScanDirection
。如果 amrescan
之后的第一次调用指定了 BackwardScanDirection
,那么匹配的索引条目集将被从后向前扫描,而不是按正常的从前向后方向扫描,因此 amgettuple
必须返回索引中最后一个匹配的元组,而不是通常返回的第一个元组。(这仅会发生在将 amcanorder
设置为 true 的访问方法上。)第一次调用后,amgettuple
必须能够从最近返回的条目开始以任一方向推进扫描。(但如果 amcanbackward
为 false,则所有后续调用都将与第一次调用具有相同的方向。)
支持有序扫描的访问方法必须支持“标记”扫描中的一个位置,并在以后返回到标记的位置。同一个位置可以被恢复多次。但是,每个扫描只需要记住一个位置;新的 ammarkpos
调用将覆盖之前标记的位置。不支持有序扫描的访问方法无需在 IndexAmRoutine
中提供 ammarkpos
和 amrestrpos
函数;而是将这些指针设置为 NULL。
扫描位置和标记位置(如果有)都必须在索引的并发插入或删除时保持一致。如果一个刚刚插入的条目没有被扫描返回(尽管在扫描开始时如果该条目存在它会被找到),或者扫描在重扫描或回溯时返回了这样一个条目,即使它在第一次扫描时没有被返回,这都是可以的。同样,并发删除可能会或可能不会在扫描结果中反映出来。重要的是插入或删除不会导致扫描遗漏或重复返回本身没有被插入或删除的条目。
如果索引存储了原始的索引数据值(而不是其有损表示),那么支持索引仅扫描是很有用的,其中索引返回实际数据,而不仅仅是堆元组的 TID。只有当可见性图显示 TID 位于一个全可见页面时,这才能避免 I/O;否则,为了检查 MVCC 可见性,仍然必须访问堆元组。但这与访问方法无关。
而不是使用 amgettuple
,可以通过 amgetbitmap
来完成索引扫描,一次性获取所有元组。这可能比 amgettuple
更有效率,因为它允许避免访问方法内的锁定/解锁循环。原则上 amgetbitmap
应具有与重复调用 amgettuple
相同的效果,但我们施加了几项限制以简化事务。首先,amgetbitmap
一次性返回所有元组,不支持标记或恢复扫描位置。其次,元组以位图的形式返回,该位图没有特定的顺序,这就是为什么 amgetbitmap
不接受 direction
参数的原因。(对于此类扫描,也不会提供排序操作符。)此外,amgetbitmap
没有提供索引仅扫描的机制,因为无法返回索引元组的内容。最后,amgetbitmap
不保证对返回的元组进行任何锁定,其影响在第 63.4 节中进行了说明。
请注意,允许访问方法只实现 amgetbitmap
而不实现 amgettuple
,或者反之亦然,如果其内部实现不适合一种 API 或另一种 API。
如果您在文档中发现任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用此表格报告文档问题。