在一次索引扫描中,索引访问方法负责吐出它被告知的、匹配 扫描键的所有元组的 TID。 访问方法不参与实际从索引的父表中取回这些 元组,也不参与判断它们是否通过扫描的可见性测试或其他 条件。
扫描键是形如
index_key operator
constant 的
WHERE 子句的内部表示,其中索引键是索引的
列之一,操作符是与该索引列关联的操作符族的成员之一。
一次索引扫描拥有零个或多个扫描键,它们被隐式地 AND 起来
— 期望返回的元组满足所有指出的条件。
对特定查询,访问方法可以报告该索引是 有损的或需要重新检查。 这意味着索引扫描将返回所有通过扫描键的条目,外加可能还有不通过的 额外条目。 核心系统的索引扫描机制随后会再次把索引条件应用到堆元组上, 验证它是否真的应当被选出。 如果未指定 recheck 选项,索引扫描必须精确返回匹配条目的 集合。
注意,确保正确找出所有且仅找出通过所有给定扫描键的条目完全是
访问方法的责任。
另外,核心系统会直接交出所有匹配索引键和操作符族的
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
不保证对返回的元组有任何加锁,其影响在
Section 63.4 中说明。
注意,如果访问方法的内部实现不适合其中一个 API,允许它只实现
amgetbitmap 而不实现
amgettuple,或者相反。