pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
在索引扫描中,索引访问方法负责返回它所知道的、匹配扫描键的所有元组的 TID。访问方法不负责从索引父表中实际取出这些元组,也不负责判断它们是否能通过扫描的可见性测试或其他条件。
扫描键是如下形式的 WHERE 子句的内部表示:index_key operator constant。其中,索引键是该索引的一列,而操作符是与该索引列关联的操作符族成员之一。一次索引扫描可以有零个或多个扫描键,这些扫描键会被隐式地以 AND 连接,也就是说,返回的元组预期应满足所有给定条件。
对于某个特定查询,访问方法可以报告该索引是有损的,或者要求重新检查。这意味着索引扫描会返回所有通过扫描键的条目,并可能额外返回一些未通过扫描键的条目。随后,核心系统的索引扫描机制会再次把索引条件应用到堆元组上,以验证它是否真的应被选中。如果没有指定重检选项,索引扫描就必须精确返回匹配条目的集合。
请注意,确保正确找出通过全部给定扫描键的所有且仅有的条目,这项工作完全由访问方法负责。此外,核心系统只是简单地把所有与索引键和操作符族匹配的 WHERE 子句交给访问方法,而不会做任何语义分析来判断它们是否冗余或互相矛盾。例如,给定 WHERE x > 4 AND x > 14,其中 x 是一个 B-树索引列,那么由 B-树的 amrescan 函数负责识别第一个扫描键是冗余的并可被丢弃。amrescan 期间需要做多少预处理,取决于索引访问方法需要在多大程度上把扫描键归约成一种“正规化”形式。
某些访问方法会按明确定义的顺序返回索引条目,另一些则不会。实际上,访问方法支持有序输出有两种不同方式:
总是按数据自然顺序返回条目的访问方法(例如 btree)应把 pg_am.amcanorder 设为真。目前,这类访问方法必须对其等值和排序操作符使用与 btree 兼容的策略号。
支持排序操作符的访问方法应把 pg_am.amcanorderbyop 设为真。这表示索引能够按满足 ORDER BY index_key operator constant 的顺序返回条目。前面已经提到,这种形式的扫描修饰符可以传给 amrescan。
amgettuple 函数有一个 direction 参数,它可以是 ForwardScanDirection(通常情况)或 BackwardScanDirection。如果 amrescan 之后的第一次调用指定了 BackwardScanDirection,那么匹配条件的索引条目集合就要按从后到前的方向扫描,而不是通常的从前到后,因此 amgettuple 必须返回索引中最后一个匹配元组,而不是通常情况下的第一个。(这只会发生在把 amcanorder 设为真的访问方法上。)第一次调用之后,amgettuple 必须准备好从最近一次返回条目的位置继续按任一方向推进扫描。(但如果 pg_am.amcanbackward 为假,则后续所有调用的方向都必须与第一次相同。)
支持有序扫描的访问方法必须支持在扫描中“标记”一个位置,并在之后返回到该标记位置。同一个位置可能会被恢复多次。不过,每次扫描只需要记住一个位置;新的 ammarkpos 调用会覆盖先前标记的位置。不支持有序扫描的访问方法仍应在 pg_am 中提供标记和恢复函数,但让这些函数在被调用时报错也是可以的。
无论是扫描位置还是标记位置(如果有),在面对索引中的并发插入或删除时都必须保持一致。如果某个新插入的条目没有被一次扫描返回,而假如该条目在扫描开始前就已存在则本应被返回,这也是可以接受的;同样,即使某个条目在第一次扫描通过时未被返回,后续重新扫描或反向扫描时返回它也是可以接受的。类似地,并发删除也可能会或者不会反映在扫描结果中。重要的是,插入或删除本身不能导致扫描漏掉,或者重复返回那些本身并未被插入或删除的条目。
Instead of using amgettuple, an index scan can be done with amgetbitmap to fetch all tuples in one call. This can be noticeably more efficient than amgettuple because it allows avoiding lock/unlock cycles within the access method. In principle amgetbitmap should have the same effects as repeated amgettuple calls, but we impose several restrictions to simplify matters. First of all, amgetbitmap returns all tuples at once and marking or restoring scan positions isn't supported. 其次,元组是以位图形式返回的,没有任何特定顺序,这也正是 amgetbitmap 不接受 direction 参数的原因。(这种扫描也永远不会提供排序操作符。) Finally, amgetbitmap does not guarantee any locking of the returned tuples, with implications spelled out in 第 52.4 节.
请注意,如果访问方法的内部实现并不适合某一个 API,那么它可以只实现 amgetbitmap 而不实现 amgettuple,反之亦然。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。