每个索引访问方法都由 pg_am 系统目录中的一行来描述。pg_am 条目指定了索引访问方法的名称和处理函数。可以使用 CREATE ACCESS METHOD 和 DROP ACCESS METHOD SQL 命令创建和删除这些条目。
必须将索引访问方法处理函数声明为接受一个 internal 类型的参数并返回伪类型 index_am_handler。该参数是一个虚拟值,仅用于防止处理函数被直接从 SQL 命令调用。该函数的结果必须是一个类型为 IndexAmRoutine 的 palloc'd 结构,其中包含核心代码需要了解的所有信息才能使用索引访问方法。IndexAmRoutine 结构,也称为访问方法的API 结构,包括指定访问方法的各种固定属性的字段,例如它是否可以支持多列索引。更重要的是,它包含指向访问方法支持函数的指针,这些函数执行访问索引的所有实际工作。这些支持函数是纯 C 函数,在 SQL 级别不可见或不可调用。这些支持函数在第 62.2 节中描述。
结构 IndexAmRoutine 的定义如下
typedef struct IndexAmRoutine
{
NodeTag type;
/*
* Total number of strategies (operators) by which we can traverse/search
* this AM. Zero if AM does not have a fixed set of strategy assignments.
*/
uint16 amstrategies;
/* total number of support functions that this AM uses */
uint16 amsupport;
/* opclass options support function number or 0 */
uint16 amoptsprocnum;
/* does AM support ORDER BY indexed column's value? */
bool amcanorder;
/* does AM support ORDER BY result of an operator on indexed column? */
bool amcanorderbyop;
/* does AM support backward scanning? */
bool amcanbackward;
/* does AM support UNIQUE indexes? */
bool amcanunique;
/* does AM support multi-column indexes? */
bool amcanmulticol;
/* does AM require scans to have a constraint on the first index column? */
bool amoptionalkey;
/* does AM handle ScalarArrayOpExpr quals? */
bool amsearcharray;
/* does AM handle IS NULL/IS NOT NULL quals? */
bool amsearchnulls;
/* can index storage data type differ from column data type? */
bool amstorage;
/* can an index of this type be clustered on? */
bool amclusterable;
/* does AM handle predicate locks? */
bool ampredlocks;
/* does AM support parallel scan? */
bool amcanparallel;
/* does AM support parallel build? */
bool amcanbuildparallel;
/* does AM support columns included with clause INCLUDE? */
bool amcaninclude;
/* does AM use maintenance_work_mem? */
bool amusemaintenanceworkmem;
/* does AM summarize tuples, with at least all tuples in the block
* summarized in one summary */
bool amsummarizing;
/* OR of parallel vacuum flags */
uint8 amparallelvacuumoptions;
/* type of data stored in index, or InvalidOid if variable */
Oid amkeytype;
/* interface functions */
ambuild_function ambuild;
ambuildempty_function ambuildempty;
aminsert_function aminsert;
aminsertcleanup_function aminsertcleanup;
ambulkdelete_function ambulkdelete;
amvacuumcleanup_function amvacuumcleanup;
amcanreturn_function amcanreturn; /* can be NULL */
amcostestimate_function amcostestimate;
amoptions_function amoptions;
amproperty_function amproperty; /* can be NULL */
ambuildphasename_function ambuildphasename; /* can be NULL */
amvalidate_function amvalidate;
amadjustmembers_function amadjustmembers; /* can be NULL */
ambeginscan_function ambeginscan;
amrescan_function amrescan;
amgettuple_function amgettuple; /* can be NULL */
amgetbitmap_function amgetbitmap; /* can be NULL */
amendscan_function amendscan;
ammarkpos_function ammarkpos; /* can be NULL */
amrestrpos_function amrestrpos; /* can be NULL */
/* interface functions to support parallel index scans */
amestimateparallelscan_function amestimateparallelscan; /* can be NULL */
aminitparallelscan_function aminitparallelscan; /* can be NULL */
amparallelrescan_function amparallelrescan; /* can be NULL */
} IndexAmRoutine;
为了有用,索引访问方法还必须在 pg_opfamily, pg_opclass, pg_amop 和 pg_amproc 中定义一个或多个操作符族和操作符类。这些条目允许规划器确定哪种类型的查询限定符可以与此访问方法的索引一起使用。操作符族和类在第 36.16 节中描述,这是阅读本章的先决材料。
单个索引由一个 pg_class 条目定义,该条目将其描述为物理关系,以及一个 pg_index 条目,该条目显示索引的逻辑内容 — 即它具有的索引列的集合以及这些列的语义,如相关的操作符类所捕获的那样。索引列(键值)可以是底层表的简单列,也可以是表行的表达式。索引访问方法通常对索引键值来自何处不感兴趣(它总是被传递预先计算的键值),但它将非常关注 pg_index 中的操作符类信息。这两个目录条目都可以作为传递给索引上所有操作的 Relation 数据结构的一部分访问。
IndexAmRoutine 的一些标志字段具有不明显的含义。amcanunique 的要求在第 62.5 节中讨论。amcanmulticol 标志声明该访问方法支持多键列索引,而 amoptionalkey 声明它允许扫描没有为第一个索引列给出任何可索引限制子句的情况。当 amcanmulticol 为 false 时,amoptionalkey 本质上说明该访问方法是否支持没有任何限制子句的全索引扫描。支持多个索引列的访问方法必须支持省略对第一个之后的任何或所有列的限制的扫描;但是,允许它们要求第一个索引列出现一些限制,这通过将 amoptionalkey 设置为 false 来表示。索引的其中一个原因是AM可能会将 amoptionalkey 设置为 false,如果它不索引空值。由于大多数可索引的操作符都是严格的,因此不能为 null 输入返回 true,因此乍一看,不存储 null 值的索引条目是很有吸引力的:无论如何它们永远不会被索引扫描返回。但是,当索引扫描对给定的索引列没有限制子句时,此参数将失败。实际上,这意味着 amoptionalkey 为 true 的索引必须索引 null,因为规划器可能会决定在没有任何扫描键的情况下使用此类索引。一个相关的限制是,支持多个索引列的索引访问方法必须支持索引第一个之后列中的空值,因为规划器会假设该索引可用于不限制这些列的查询。例如,考虑一个 (a,b) 上的索引和一个带有 WHERE a = 4 的查询。系统将假设该索引可用于扫描 a = 4 的行,如果索引省略了 b 为 null 的行,则这是错误的。但是,省略第一个索引列为 null 的行是可以的。索引 null 值的索引访问方法还可以设置 amsearchnulls,表示它支持 IS NULL 和 IS NOT NULL 子句作为搜索条件。
amcaninclude 标志指示访问方法是否支持“包含”列,即它可以存储(无需处理)除键列之外的其他列。上一段的要求仅适用于键列。特别是,amcanmulticol=false 和 amcaninclude=true 的组合是合理的:它意味着只能有一个键列,但也可以有包含的列。此外,必须允许包含的列为空,这与 amoptionalkey 无关。
amsummarizing 标志指示访问方法是否总结索引的元组,总结粒度至少为每个块。不指向单个元组而是指向块范围的访问方法(如BRIN)可能会允许HOT优化继续。这不适用于索引谓词中引用的属性,更新此类属性始终会禁用HOT.
如果您发现文档中有任何不正确、与您使用特定功能的体验不符或需要进一步澄清的地方,请使用此表单报告文档问题。