インデックスアクセスメソッド関数

PostgreSQL 8.4.1文書
前のページ | 巻戻し | 第 50章インデックスアクセスメソッドのインタフェース定義 | 早送り | 次のページ

# 50.2. インデックスアクセスメソッド関数

インデックスアクセスメソッドが提供しなければならない、インデックス構築および保守関数を以下に示します。

    IndexBuildResult *
    ambuild (Relation heapRelation,
             Relation indexRelation,
             IndexInfo *indexInfo);

新しいインデックスを構築します。 空のインデックスリレーションが物理的に作成されます。 これは、アクセスメソッドが必要とする何らかの固定データと、テーブル内に既存のすべてのタプルに対応する項目が書き込まれなければなりません。 通常、`ambuild`関数は`IndexBuildHeapScan()`を呼び出し、既存のタプルをテーブルからスキャンし、インデックスに挿入しなければならないキーを計算します。 この関数は、新しいインデックスに関する統計情報を含むpallocされた構造体を返さなければなりません。

    bool
    aminsert (Relation indexRelation,
              Datum *values,
              bool *isnull,
              ItemPointer heap_tid,
              Relation heapRelation,
              bool check_uniqueness);

既存のインデックスに新しいタプルを挿入します。 `values`配列と `isnull`配列がインデックスされるキー値を提供するもので、`heap_tid`がインデックスされるTIDです。 アクセスメソッドが一意なインデックスをサポートする場合（その`pg_am`.`amcanunique`が真の場合）、`check_uniqueness`は真を取る可能性があります。 この場合、アクセスメソッドでは、競合する行が存在しないことを検証しなければなりません。 通常これは、アクセスメソッドが`heapRelation`を必要とする唯一の状況です。 詳細は項50.5を参照してください。 インデックスが挿入された場合、TRUEが返されます。 挿入されなかった場合、FALSEが返されます。 （FALSEという結果はエラー条件を表すものではありませんが、インデックスメソッドがNULLに対するインデックスを拒絶する場合にも使用されます。）

    IndexBulkDeleteResult *
    ambulkdelete (IndexVacuumInfo *info,
                  IndexBulkDeleteResult *stats,
                  IndexBulkDeleteCallback callback,
                  void *callback_state);

インデックスからタプル（複数可）を削除します。 これは"一括削除"操作を行いますが、インデックス全体をスキャンし、各項目に対して削除すべきかどうか検査を行うように実装されることが想定されています。 渡される`callback`関数は、`callback(`TID`, callback_state) returns bool`という形で、参照用TIDで識別されるインデックス項目を削除すべきかどうか決定するために呼び出さなければなりません。 NULLまたはpallocした削除操作の影響に関する統計情報を含む構造体を返さなければなりません。 `amvacuumcleanup`に渡さなければならない情報がなければ、NULLを返しても問題ありません。

`maintenance_work_mem`の制限により、多くのタプルが削除される時、`ambulkdelete`を複数回呼び出す必要があるかもしれません。 `stats`引数は、このインデックスに対する前回の呼び出し結果です。 （`VACUUM`操作における最初の呼び出しではこれはNULLです。） これにより、AMは操作全体に跨った統計情報を計算することができます。 典型的に、渡された`stats`がNULLでない場合、`ambulkdelete`は同じ構造体を変更し、返します。

    IndexBulkDeleteResult *
    amvacuumcleanup (IndexVacuumInfo *info,
                     IndexBulkDeleteResult *stats);

`VACUUM`操作（0回以上の`ambulkdelete`呼び出し）後の整理を行います。 これは、インデックス統計情報を返す以上の処理を行う必要はありません。 しかし、空のインデックスページの回収などの一括整理を行う可能性があります。 `stats`は、最後の`ambulkdelete`呼び出しが返したものです。 削除する必要があるタプルが存在しなかったために`ambulkdelete`が呼び出されなかった場合はNULLとなります。 結果はNULLでなければ、pallocされた構造体でなければなりません。 含まれる統計情報は`pg_class`を更新するために使用され、また、`VERBOSE`が指定された`VACUUM`によって報告されます。 `VACUUM`操作の間にインデックスがまったく変わらなかった場合はNULLを返しても問題ありません。 しかし、そうでなければ正しい統計情報を返さなければなりません。

PostgreSQL 8.4の時点で、`amvacuumcleanup`も`ANALYZE`操作の完了時点で同様呼ばれます。この場合、`stats`は常にNULLで、戻り値は無視されます。この事象は`info->analyze_only`を検査することで識別されます。アクセスメソッドがそのような呼び出しで挿入後の掃除以外何もしないように、そしてそれは自動vacuumワーカプロセスのみであるようにすることを推奨します。

    void
    amcostestimate (PlannerInfo *root,
                    IndexOptInfo *index,
                    List *indexQuals,
                    RelOptInfo *outer_rel,
                    Cost *indexStartupCost,
                    Cost *indexTotalCost,
                    Selectivity *indexSelectivity,
                    double *indexCorrelation);

インデックススキャンのコストを推定します。 この関数については後述の項50.6で説明します。

    bytea *
    amoptions (ArrayType *reloptions,
               bool validate);

インデックス用のreloptionsの解析と検証を行います。 インデックスに非NULLのreloptions配列が存在する場合にのみ呼び出されます。 `reloptions`は、`name``=``value`形式の項目からなる、`text`型の配列です。 この関数は`bytea`型の値を生成しなければならず、この値はインデックスのrelcache項目の`rd_options`フィールドにコピーされます。 `bytea`型の値の内容はアクセスメソッドが独自に定義できるように開放されています。 標準のアクセスメソッドのほとんどはすべて`StdRdOptions`構造体を使用します。 `validate`が真の場合、何らかのオプションが認識できなかった場合や無効な値が存在した場合、この関数は適切なエラーメッセージを報告しなければなりません。 `validate`が偽の場合、無効な項目は単に無視されます。 （読み込みオプションが既に`pg_catalog`に格納されている場合`validate`は偽です。 アクセスメソッドがそのオプション用の規則を変更した場合にのみ、無効な項目が検出されます。 そして、その場合、古い項目を無視することが適切です。 デフォルトの動作を行わせたい場合はNULLを返しても問題ありません。 ）

当然ながらインデックスの目的は、よく修飾子やスキャンキーと呼ばれる、インデックス可能な`WHERE`条件を満たすタプルのスキャンをサポートすることです。 インデックススキャンのセマンティックスは、後で項50.3でより詳しく説明します。インデックスアクセスメソッドは"単純"インデックススキャン、"ビットマップ"インデックススキャン、またはこれら双方を提供します。 インデックスアクセスメソッドが提供しなければならない、もしくは提供する可能性のあるスキャン関連の関数を以下に示します。

    IndexScanDesc
    ambeginscan (Relation indexRelation,
                 int nkeys,
                 ScanKey key);

新しいスキャンを開始します。 （`nkeys`長の）`key`配列は、インデックススキャン用のスキャンキー（複数可）を記述します。 結果は、pallocした構造体でなければなりません。 実装上の理由により、インデックスアクセスメソッドは`RelationGetIndexScan()`呼び出しによってこの構造体を作成しなければなりません。 ほとんどの場合、`ambeginscan`自体はこの呼び出しの他にはほとんど何も行いません。 インデックス起動の興味深い部分は、`amrescan`にあります。

    boolean
    amgettuple (IndexScanDesc scan,
                ScanDirection direction);

指定されたスキャン内から指定された方向（インデックス内の前方または後方）で次のタプルを取り出します。 タプルを取り出した場合はTRUEを返します。 一致するタプルが残っていない場合はFALSEを返します。 TRUEの場合、そのタプルのTIDが`scan`に格納されます。 "成功"とは、単にインデックスにスキャンキーに一致する項目があったことを意味しているだけです。 タプルが必ずヒープ内に存在することや、呼び出し元のスナップショットの試験を通過したことを意味してはいません。 成功の暁には、`amgettuple`は`scan->xs_recheck`を真か偽かに設定しなければなりません。偽の意味は、インデックス項目がスキャンキーに一致することです。真の意味は、これが確かなことではなく、スキャンキーで表示された条件がヒープタプルを取り出された後で再検査されなければならないことです。この対策は"非可逆"インデックス演算子を支援します。再検査はスキャン条件のみに拡大適用されることに注意してください。部分インデックス述語（もしあれば）は`amgettuple`呼び出し子で決して再検査されません。

`amgettuple`関数は、アクセスメソッドが"単純"インデックススキャンを支援するときのみ提供される必要があります。そうでなければ、`pg_am`行の`amgettuple`フィールドはゼロに設定されなければなりません。

    int64
    amgetbitmap (IndexScanDesc scan,
                 TIDBitmap *tbm);

指定されたスキャンから全てのタプルを取り出し、呼び出し側が供給するTIDBitmapにそれらを付加します（と言うことは、既にあるビットマップにタプルIDの集合にORを取ります）。取り出されるタプル数は返されます（例えば幾つかのAMが重複を検出しないので、これは単なる概算です）。タプルIDをビットマップに挿入する間、`amgetbitmap`は特定のタプルIDに必要なスキャン条件の再検査を示すことが可能です。これは`amgettuple`の`xs_recheck`出力パラメータに類似しています。注意：現在の実装においてこの機能の提供はビットマップそのものの非可逆格納を提供するのに結びついていて、従い呼び出し側はスキャン条件と部分インデックスの述部（存在すれば）を再検査可能なタプルに対して再検査します。とは言っても常に正しいとは限りません。 `amgetmulti`および`amgettuple`を同じインデックススキャン内で使用することはできません。 項50.3で説明した通り、`amgetbitmap`を使用する場合には他にも制限があります。

`amgetbitmap`関数はアクセスメソッドが"ビットマップ"インデックススキャンを提供している場合のみ必要です。そうでなければ、`pg_am`行の中の`amgetbitmap`フィールドはゼロに設定されなければなりません。

    void
    amrescan (IndexScanDesc scan,
              ScanKey key);

指定されたスキャンを再起動します。 スキャンキーを新しくすることもできます。 （古いキーのまま継続するには、`key`にNULLを渡します。） キーの数を変更することはできないことに注意してください。 実際には、入れ子状ループ結合によって新しい外部タプルが選択され、同じスキャンキー構造体で新しいキー比較値が必要とされた場合に、この再起動機能は使用されます。 再スキャンだけではなくインデックススキャンの初期設定にも使用されますので、この関数はまた、`RelationGetIndexScan()`からも呼び出されます。

    void
    amendscan (IndexScanDesc scan);

スキャンを停止し、リソースを解放します。 `scan`構造体自体は解放すべきではありません。 アクセスメソッドで内部的に取られたロックやピンは解放しなければなりません。

    void
    ammarkpos (IndexScanDesc scan);

現在のスキャン位置を記録します。 アクセスメソッドは1スキャン当たり1つの記録済みスキャンのみをサポートしなければなりません。

    void
    amrestrpos (IndexScanDesc scan);

もっとも最近に記録された位置にスキャンを戻します。

簡便性のために、インデックスアクセスメソッド関数の`pg_proc`項目は、正確な引数の数を示さなければなりません。 しかし、それらはすべて`internal`型として宣言します。 （引数のほとんどがSQLでは未知の型を持つため、ユーザがこうした関数を直接呼び出すことを防ぐことがこの理由です。） 戻り値の型は、`void`、`internal`、`boolean`のいずれかで適切に宣言されます。 唯一の例外は`amoptions`です。 これは、`text[]`および`bool`を取り`bytea`を返すように正しく宣言しなければなりません。 この規定により、クライアントコードは`amoptions`を実行してオプションの設定の有効性を検査することができます。

前のページ | ホーム | 次のページ
インデックス用のカタログ項目 | 上に戻る | インデックススキャン