ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 54.1\. 索引的系统表记录 每个索引访问方法都在系统表`pg_am`里面用一行来描述(参阅[Section 47.3](#calibre_link-1492))。 一个`pg_am`行的主要内容是引用[`pg_proc`](#calibre_link-743) 里面的记录,用来标识索引访问方法提供的索引访问函数。 这些函数的接口(API)在本章后面描述。另外,`pg_am`的数据行声明了几个索引访问方法的固定属性,比如,它是否支持多字段索引。 目前还没有创建、删除`pg_am`记录的特殊支持;任何想写这么一个新的访问方法的人都需要能够自己向这个表里面插入合适的新行。 要想有真正用处,一个索引访问方法还必须有一个或多个_操作符族_和_操作符类_,定义在 [`pg_opfamily`](#calibre_link-732), [`pg_opclass`](#calibre_link-710), [`pg_amop`](#calibre_link-1493)和 [`pg_amproc`](#calibre_link-1494)里面。 这些记录允许规划器判断哪些查询的条件可以适用于用这个索引访问方法创建的索引。 操作符族和操作符类在[Section 35.14](#calibre_link-54)里面定义,是读取本章的前提之一。 一个独立的索引是由一行 [`pg_class`](#calibre_link-578) 记录以物理关系的方式描述的,加上一个[`pg_index`](#calibre_link-707) 行,表示该索引的逻辑内容 —也就是说,它所拥有的索引字段集,以及被相关的操作符类捕获的这些字段的语义。 索引字段(键值)可以是下层表的字段,也可以是该表的数据行上的表达式。 索引访问方法通常不关心索引的键值来自哪里(它总是操作经过预计算的键值),但是它会对`pg_index`里面的操作符类信息很感兴趣。 所有这些系统表记录都可以当作`Relation`数据结构的一部分访问,这个数据结构会被传递到对该索引的所有操作上。 `pg_am`中的有些标志字段的含义并不那么直观。 `amcanunique`的需求在[Section 54.5](#calibre_link-1170)里讨论, `amcanmulticol`标志断言该索引访问方法支持多字段索引, `amoptionalkey`断言它允许对那种在第一个索引字段上没有给出可索引限制子句的扫描。 如果`amcanmulticol`为假,那么`amoptionalkey` 实际上说的是该访问方法是否允许不带限制子句的全索引扫描。 那些支持多字段索引的访问访法必须支持那些在省略了除第一个字段以外的其它字段的约束的扫描; 不过,系统允许这些访问访法要求在第一个字段上出现一些限制,这一点是通过把 amoptionalkey 设置为假来实现的。 一个访问访法可能设置`amoptionalkey`为假,如果它不索引NULL值的话。 因为大多数可以索引的操作符都是严格的,因此不能对 NULL 输入返回 TRUE ,所以,第一眼看见会觉得不为 NULL 存储索引记录的想法很吸引人:因为他们不可能被一个索引扫描返回。 不过,这个想法在一个给出的索引字段上没有限制子句的索引扫描的情况下就不行了;这样的扫描应该包括 NULL 行。 实际上,这意味着设置了`amoptionalkey`为真的索引必须索引 NULL值 ,因为规划器可能会决定在根本没有扫描键字的时候使用这样的索引。 这样的索引必须可以在完全没有扫描键字的情况下运行。 另外一个限制是一个支持多字段索引的索引访问方法_必须_索引第一个字段后面的字段的 NULL值,因为规划器会认为这个索引可以用于那些没有限制这些字段的查询。 比如,假设有个在(a,b)上的索引,而一个查询的条件是`WHERE a = 4`。系统会认为这个索引可以用于扫描`a = 4`的数据行,如果索引忽略了`b`为空的数据行,那么就是错误的。 不过,如果第一个索引字段值是空,那么忽略它是 OK 的。 一个索引NULL值的索引访问方法可能会设置`amsearchnulls`, 表明它支持`IS NULL` 和 `IS NOT NULL`子句作为搜索条件。