每个索引访问方法都由系统目录 pg_am
中的一行来描述。pg_am
条目指定索引访问方法的名称和处理函数。可以使用 CREATE ACCESS METHOD 和 DROP ACCESS METHOD SQL 命令创建和删除这些条目。
索引访问方法处理函数必须声明为接受一个 internal
类型的单个参数,并返回伪类型 index_am_handler
。该参数是一个虚拟值,仅用于防止处理函数直接从 SQL 命令调用。函数的结果必须是一个 palloc'd IndexAmRoutine
类型的结构,其中包含核心代码使用索引访问方法所需知道的一切。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,因此一开始不存储空值的索引条目很有吸引力:它们无论如何都不会被索引扫描返回。但是,当索引扫描对给定的索引列没有限制子句时,此论点失败。实际上,这意味着 amoptionalkey
为 true 的索引必须索引 null,因为规划器可能会决定使用没有扫描键的此类索引。一个相关的限制是,支持多个索引列的索引访问方法必须支持在第一个之后的列中索引 null 值,因为规划器会假定该索引可以用于不限制这些列的查询。例如,考虑一个 (a,b) 上的索引和一个带有 WHERE a = 4
的查询。系统将假定该索引可用于扫描 a = 4
的行,如果索引省略 b
为 null 的行,则这是错误的。但是,省略第一个索引列为 null 的行是可以的。索引 null 值的索引访问方法还可以设置 amsearchnulls
,表示它支持将 IS NULL
和 IS NOT NULL
子句作为搜索条件。
amcaninclude
标志指示访问方法是否支持“包含”列,即它可以存储(不处理)超出键列的附加列。上一段的要求仅适用于键列。特别是,amcanmulticol
=false
和 amcaninclude
=true
的组合是合理的:这意味着只能有一个键列,但也可以有包含的列。此外,包含的列必须允许为 null,独立于 amoptionalkey
。
amsummarizing
标志表示访问方法是否汇总索引的元组,汇总粒度至少为每个块。不指向单个元组而是指向块范围(如BRIN)的访问方法,可能会允许HOT优化继续进行。这不适用于索引谓词中引用的属性,此类属性的更新始终禁用HOT.
如果您在文档中看到任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。