2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:开发版
不支持的版本:11 / 10 / 9.6

62.1. 索引的基本 API 结构 #

每个索引访问方法都由pg_am系统目录中的一行描述。 pg_am条目指定了索引访问方法的名称和一个处理程序函数。可以使用CREATE ACCESS METHODDROP 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_opfamilypg_opclasspg_amoppg_amproc中定义的操作符族操作符类。这些条目允许计划程序确定哪些类型的查询限定符可以与这种访问方法的索引一起使用。操作符族和类在第36.16节中进行了描述,这是阅读本章的先决条件。

单个索引由pg_class条目定义,该条目将其描述为一个物理关系,以及一个pg_index条目,该条目显示索引的逻辑内容——即它具有的索引列集以及这些列的语义,如关联的操作符类所捕获的那样。索引列(键值)可以是基础表的简单列,也可以是表行上的表达式。索引访问方法通常对索引键值来自何处不感兴趣(它始终传递预计算的键值),但它会非常关注pg_index中的操作符类信息。这两个目录条目都可以作为传递给索引上所有操作的Relation数据结构的一部分进行访问。

IndexAmRoutine的一些标志字段具有不明显的含义。amcanunique的要求在第62.5节中进行了讨论。amcanmulticol标志断言访问方法支持多键列索引,而amoptionalkey断言它允许扫描其中没有为第一个索引列给出可索引限制子句。当amcanmulticol为false时,amoptionalkey基本上表示访问方法是否支持没有任何限制子句的完整索引扫描。支持多个索引列的访问方法必须支持省略第一个列之后的所有或任何列上的限制的扫描;但是,它们可以要求某些限制出现在第一个索引列中,这通过将amoptionalkey设置为false来指示。索引可能设置amoptionalkey为false的一个原因是它不索引空值。由于大多数可索引操作符都是严格的,因此无法对空输入返回true,因此从表面上看,不存储空值的索引条目很有吸引力:无论如何,它们永远不会被索引扫描返回。但是,当索引扫描对给定索引列没有限制子句时,此参数将失败。在实践中,这意味着amoptionalkey为true的索引必须索引空值,因为计划程序可能会决定在没有任何扫描键的情况下使用此类索引。相关的限制是,支持多个索引列的索引访问方法必须支持索引第二个及以后列中的空值,因为计划程序将假设索引可用于不限制这些列的查询。例如,考虑对(a,b)的索引和具有WHERE a = 4的查询。系统将假设索引可用于扫描a = 4的行,如果索引省略了b为空的行,则这是错误的。但是,省略第一个索引列为空的行是可以的。索引空值的索引访问方法也可以设置amsearchnulls,表示它支持IS NULLIS NOT NULL子句作为搜索条件。AM可能设置amoptionalkey为false的原因是它不索引空值。由于大多数可索引操作符都是严格的,因此无法对空输入返回true,因此从表面上看,不存储空值的索引条目很有吸引力:无论如何,它们永远不会被索引扫描返回。但是,当索引扫描对给定索引列没有限制子句时,此参数将失败。在实践中,这意味着amoptionalkey为true的索引必须索引空值,因为计划程序可能会决定在没有任何扫描键的情况下使用此类索引。相关的限制是,支持多个索引列的索引访问方法必须支持索引第二个及以后列中的空值,因为计划程序将假设索引可用于不限制这些列的查询。例如,考虑对(a,b)的索引和具有WHERE a = 4的查询。系统将假设索引可用于扫描a = 4的行,如果索引省略了b为空的行,则这是错误的。但是,省略第一个索引列为空的行是可以的。索引空值的索引访问方法也可以设置amsearchnulls,表示它支持IS NULLIS NOT NULL子句作为搜索条件。

The amcaninclude标志指示访问方法是否支持包含列,即它可以在键列之外存储(无需处理)其他列。前一段的要求仅适用于键列。特别是,amcanmulticol=falseamcaninclude=true的组合是合理的:这意味着只能有一个键列,但也可以有包含列。此外,包含列必须允许为空,而与amoptionalkey无关。

The amsummarizing标志指示访问方法是否汇总索引元组,汇总粒度至少为每个块。不指向单个元组,而是指向块范围(如BRIN)的访问方法,可能允许HOT优化继续。这并不适用于索引谓词中引用的属性,此类属性的更新始终禁用HOT.

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用此表单报告文档问题。