2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:开发版
不受支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1

62.3. 索引扫描 #

在索引扫描中,索引访问方法负责返回所有它被告知匹配扫描键的元组的TID。访问方法参与实际从索引的父表中获取这些元组,也不参与确定它们是否通过扫描的可见性测试或其他条件。

扫描键是WHERE子句的内部表示形式,其格式为index_key operator constant,其中索引键是索引的列之一,运算符是与该索引列关联的运算符族中的一个成员。索引扫描具有零个或多个扫描键,这些键被隐式地进行AND运算——返回的元组预计要满足所有指示的条件。

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

请注意,完全由访问方法来确保它正确地找到所有且仅找到通过所有给定扫描键的条目。此外,核心系统将简单地传递所有与索引键和运算符族匹配的WHERE子句,而不会进行任何语义分析以确定它们是否冗余或矛盾。例如,给定WHERE x > 4 AND x > 14,其中x是b树索引列,则由b树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中提供ammarkposamrestrpos函数;而是将这些指针设置为NULL。

在索引中并发插入或删除时,必须一致地维护扫描位置和标记位置(如果有)。如果新插入的条目未被扫描返回(如果该条目在扫描开始时存在,则扫描会找到该条目),或者扫描在重新扫描或备份时返回该条目(即使它在第一次扫描时未被返回),这都是可以的。类似地,并发删除可能会或可能不会反映在扫描的结果中。重要的是,插入或删除不会导致扫描错过或重复返回未被插入或删除的条目。

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

索引扫描可以使用amgetbitmap而不是amgettuple来获取所有元组,一次调用即可完成。这可能比amgettuple更有效,因为它允许避免访问方法中的锁定/解锁循环。原则上,amgetbitmap应该与重复的amgettuple调用具有相同的效果,但为了简化问题,我们对它施加了一些限制。首先,amgetbitmap一次返回所有元组,并且不支持标记或恢复扫描位置。其次,元组以位图的形式返回,位图没有任何特定的顺序,这就是为什么amgetbitmap不采用direction参数的原因。(对于此类扫描,永远不会提供排序运算符。)此外,没有为amgetbitmap提供仅索引扫描的规定,因为无法返回索引元组的内容。最后,amgetbitmap不保证对返回的元组进行任何锁定,其影响在第62.4节中说明。

请注意,如果访问方法的内部实现不适合某个API,则允许它仅实现amgetbitmap而不实现amgettuple,反之亦然。

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用此表单报告文档问题。