各インデックスメソッドはpg_am
システムカタログの行で説明されます。
pg_am
エントリはインデックスアクセスメソッドの名前とハンドラ関数を指定します。
これらのエントリはSQLコマンドCREATE ACCESS METHODとDROP ACCESS METHODを使って、作成および削除することができます。
インデックスメソッドのハンドラ関数は、internal
型の引数を1つ取り、疑似型index_am_handler
を返すものとして宣言しなければなりません。
引数は単にハンドラ関数がSQLコマンドから直接呼び出されるのを防ぐためのダミーの値です。
関数の結果は型IndexAmRoutine
のpallocされた構造体でなければならず、そこにはインデックスアクセスメソッドを使用するためにコアコードが知っている必要のあるすべてのことが含まれています。
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 columns included with clause INCLUDE? */ bool amcaninclude; /* does AM use maintenance_work_mem? */ bool amusemaintenanceworkmem; /* 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; 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
内で定義される、複数の演算子族と演算子クラスを持ちます。
これらの項目により、プランナは、このアクセスメソッドのインデックスがどのような問い合わせ条件に対して使用できるかを決定することができます。
演算子族と演算子クラスについては、38.16で説明します。
これは本章を読む上で必要となる資料です。
個々のインデックスは、インデックスを物理的なリレーションとして記述するpg_class
項目と、インデックスの論理的な内容、つまり、インデックスが持つインデックス列の集合とその列の意味を、関連する演算子クラスで再現されたものとして表すpg_index
項目とで定義されます。
インデックス列(キー値)は、背後のテーブルの単純な列、あるいは、テーブル行に対する式とすることができます。
通常、インデックスアクセスメソッドはインデックスキー値が何を表すかについて考慮しません。
(常に計算済みのキー値として扱われます。)
しかし、pg_index
内の演算子クラスの情報を深く考慮します。
この両方のカタログ項目は、インデックスに対するすべての操作に渡されるRelation
データ構造の一部としてアクセスすることができます。
IndexAmRoutine
のフラグフィールドの中には、意味がわかりにくいものがあります。
amcanunique
の必要条件は62.5で説明されています。
amcanmulticol
フラグはアクセスメソッドが複数キー列に対するインデックスをサポートすることを表し、amoptionalkey
は、インデックス可能な制限句が最初のインデックス列に指定されていないスキャンを許可することを表します。
amcanmulticol
が偽の場合、amoptionalkey
は基本的に、アクセスメソッドが制限句なしで完全なインデックススキャンをサポートするかどうかを表します。
複数列に対するインデックスをサポートするアクセスメソッドは、最初の列以降のすべてまたは一部の列に関する制限がなくてもスキャンをサポートしなければなりません。
しかし、最初のインデックス列にいくつかの制限を要求することは認められています。
これは、amoptionalkey
を偽に設定することで通知されます。
インデックスアクセスメソッドがamoptionalkey
を偽にする1つの理由は、NULLをインデックス付けしない場合です。
ほとんどのインデックス可能な演算子は厳密で、NULL値の入力に対して真を返すことができませんので、NULLに対してインデックス項目を格納しないことは一見魅力的です。
これはインデックススキャンによって何も返しません。
しかし、最初のインデックス列に対する制限がないインデックススキャンでは、この引数は失敗します。
プランナがこうしたスキャンキーをまったく持たないインデックスを使用することを決定する可能性がありますので、実際これは、amoptionalkey
が真のインデックスはNULLインデックスを持たなければならないことを意味します。
関連する制限として、プランナはこれらの列を制限しない問い合わせでインデックスを使用できることを前提とするため、複数のインデックス列をサポートするインデックスアクセスメソッドは1番目の後の列でNULL値のインデックスをサポートしなければならないということがあります。
例えば、(a,b)に対するインデックスに、WHERE a = 4
という条件で問い合わせを行うことを考えてみます。
システムは、このインデックスをa = 4
を持つ行をスキャンすることに使用できるものと仮定します。
これはもし、b
がNULLの場合の行をインデックスが省略する場合は間違っています。
しかし、最初のインデックス列がNULLの場合に行を省略することは問題ありません
また、NULLをインデックス付けするインデックスアクセスメソッドはamsearchnulls
を設定する可能性があります。
これは検索条件としてIS NULL
およびIS NOT NULL
句をサポートすることを示します。
amcaninclude
フラグは、このアクセスメソッドが(処理することなく)キー列以外の追加の列を格納することができる「included」列をサポートしているかどうかを示します。
前段落の要件はキー列にのみ適用されます。
とりわけ、amcanmulticol
=false
とamcaninclude
=true
の組み合わせは実用的です。
これは単一のキー列だけが存在しつつも、include列が存在することができることを示しています。
また、amoptionalkey
とは独立して、include列はNULLにすることができなければなりません。