2025年9月25日: PostgreSQL 18 釋出!
支援的版本:當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6

63.1. 索引的基本 API 結構 #

每個索引訪問方法都透過 pg_am 系統目錄中的一行進行描述。 pg_am 條目指定索引訪問方法的名稱和處理函式。可以使用 CREATE ACCESS METHODDROP ACCESS METHOD SQL 命令建立和刪除這些條目。

索引訪問方法處理函式必須宣告接受一個 internal 型別的引數,並返回偽型別 index_am_handler。該引數是一個 dummy 值,僅用於阻止從 SQL 命令直接呼叫處理函式。函式的返回值必須是一個 palloc 分配的 IndexAmRoutine 型別的結構體,其中包含核心程式碼需要知道的有關使用索引訪問方法的所有資訊。 IndexAmRoutine 結構體,也稱為訪問方法的API 結構,包含指定訪問方法各種固定屬性的欄位,例如它是否支援多列索引。更重要的是,它包含指向訪問方法支援函式的指標,這些函式執行訪問索引的所有實際工作。這些支援函式是普通的 C 函式,在 SQL 級別不可見或不可呼叫。支援函式在 第 63.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 hashing using API consistent with the hash AM? */
    bool        amcanhash;
    /* do operators within an opfamily have consistent equality semantics? */
    bool        amconsistentequality;
    /* do operators within an opfamily have consistent ordering semantics? */
    bool        amconsistentordering;
    /* 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;   /* can be NULL */
    ambulkdelete_function ambulkdelete;
    amvacuumcleanup_function amvacuumcleanup;
    amcanreturn_function amcanreturn;   /* can be NULL */
    amcostestimate_function amcostestimate;
    amgettreeheight_function amgettreeheight;   /* can be NULL */
    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 */

    /* interface functions to support planning */
    amtranslate_strategy_function amtranslatestrategy;  /* can be NULL */
    amtranslate_cmptype_function amtranslatecmptype;    /* can be NULL */
} IndexAmRoutine;

要有用,索引訪問方法還必須在 pg_opfamilypg_opclasspg_amoppg_amproc 中定義一個或多個運算子族運算子類。這些條目允許規劃器確定可以使用這種訪問方法的索引進行哪些型別的查詢限定。運算子族和類在 第 36.16 節 中進行了描述,這是閱讀本章的先決條件。

單個索引由一個 pg_class 條目定義,該條目將其描述為一個物理關係,再加上一個 pg_index 條目,該條目顯示了索引的邏輯內容 — 即,它擁有的索引列集及其關聯的運算子類捕獲的列的語義。索引列(鍵值)可以是基礎表的簡單列,也可以是基於錶行的表示式。索引訪問方法通常對索引鍵值來自何處不感興趣(它總是會獲得預先計算好的鍵值),但它會非常關心 pg_index 中的運算子類資訊。這兩個目錄條目都可以作為傳遞給索引所有操作的 Relation 資料結構的一部分進行訪問。

IndexAmRoutine 的一些標誌欄位具有非顯而易見的含義。 amcanunique 的要求在 第 63.5 節 中進行了討論。 amcanmulticol 標誌斷言該訪問方法支援多鍵列索引,而 amoptionalkey 斷言它允許在未提供第一個索引列的可索引限制子句的情況下進行掃描。當 amcanmulticol 為 false 時, amoptionalkey 實際上表示訪問方法是否支援在沒有限制子句的情況下進行全索引掃描。支援多個索引列的訪問方法必須支援可以省略第一個列之後任何或所有列的限制的掃描;但是,它們可以要求第一個索引列出現某種限制,這透過設定 amoptionalkey 為 false 來訊號。一個索引之所以AM可能設定 amoptionalkey 為 false,是因為它不索引 NULL 值。由於大多數可索引運算子是嚴格的,因此對於 NULL 輸入它們無法返回 true,因此不儲存 NULL 值的索引條目是很有吸引力的:它們無論如何都無法從索引掃描中返回。然而,當索引掃描對於給定索引列沒有限制子句時,這個論點就不成立了。實際上,這意味著 amoptionalkey 為 true 的索引必須索引 NULL,因為規劃器可能會決定完全不使用任何掃描鍵來使用這種索引。一個相關的限制是,支援多個索引列的索引訪問方法必須支援索引第一個列之後的列中的 NULL 值,因為規劃器將假定該索引可用於不限制這些列的查詢。例如,考慮一個基於 (a,b) 的索引和一個帶有 WHERE a = 4 的查詢。系統將假定該索引可用於掃描 a = 4 的行,如果索引省略了 b 為 NULL 的行,這是錯誤的。但是,省略第一個索引列為 NULL 的行是可以的。索引 NULL 的索引訪問方法也可以設定 amsearchnulls,表明它支援 IS NULLIS NOT NULL 子句作為搜尋條件。

amcaninclude 標誌表示訪問方法是否支援包含的列,即它可以儲存(無需處理)除鍵列之外的附加列。前一段的要求僅適用於鍵列。特別是, amcanmulticol=falseamcaninclude=true 的組合是合理的:它意味著只能有一個鍵列,但也可以有包含的列。此外,包含的列必須允許為 NULL,這與 amoptionalkey 無關。

amsummarizing 標誌指示訪問方法是否按塊(例如BRIN)對索引的元組進行彙總,彙總粒度至少為每個塊。不支援單獨指向元組,而是指向塊範圍的訪問方法(如HOT),可能允許該HOT.

提交更正

如果您在文件中發現任何不正確的內容、與您對特定功能的實際體驗不符的內容或需要進一步澄清的內容,請使用 此表單 報告文件問題。