インデックススキャンでは、スキャンキーに一致するものと示したすべてのタプルのTIDを繰り返すことに関する責任をインデックスアクセスメソッドが持ちます。 アクセスメソッドには、実際のインデックスの親テーブルからのタプルの取り出しやタプルがスキャンの可視性テストや他の条件を通過したかどうかの決定は含まれません。
スキャンキーは、index_key
operator
constant
という形式のWHERE
句の内部的表現です。
ここで、index_key
は、インデックス列の1つで、operator
はインデックス列に関連した演算子族のメンバの1つです。
インデックススキャンは、暗黙的にAND演算される0個以上のスキャンキーを持ちます。
返されるタプルは指定された条件を満たすものと想定されます。
アクセスメソッドはインデックスがある特定の問い合わせに対し非可逆、または再検査を要求するかどうかを報告することができます。 これは、インデックススキャンがスキャンキーを満たすすべての項目と、それに加えて、満たさない可能性のある項目を返すことを意味します。 コアシステムのインデックススキャン機構はヒープタプルに対し、本当に選択されるべきかどうかを検証するためにその演算子をインデックス条件に再度適用します。 再検査オプションが指定されない場合、インデックススキャンは一致する項目の集合を返さなければなりません。
確実に、指定されたスキャンキーすべてに一致するもののみをすべて正しく見つけ出すことは、完全にアクセスメソッドの責任であることに注意してください。
また、コアシステムは、冗長かどうかや矛盾するかどうかを決定するための意味的な解析を行わず、単にインデックスキーと演算子族に一致するWHERE
句をすべて渡します。
例えば、WHERE x > 4 AND x > 14
があり、x
がB-treeインデックス列であったとすると、これは、B-tree amrescan
関数に任されて、最初のスキャンキーが冗長であり、無視できることが認知されます。
amrescan
における前処理の必要性は、インデックスアクセスメソッドがスキャンキーを「正規化」形式にする必要があるかどうかに依存します。
一部のアクセスメソッドは、他では行いませんが、十分に定義された順序でインデックス項目を返します。 アクセスメソッドが出力の順序付けをサポートできるようにする方法は、実質2種類存在します。
常にそのデータ(btreeなど)の自然な順序で項目を返すアクセスメソッドはamcanorder
を真に設定しなければなりません。
現在、こうしたアクセスメソッドは、その等価性と順序付け演算子でbtree互換の戦略番号を使用しなければなりません。
順序付け演算子をサポートするアクセスメソッドはamcanorderbyop
を真に設定しなければなりません。
これは、インデックスがORDER BY
index_key
operator
constant
を満たす順序で項目を返すことができることを示します。
前述の通り、この形式のスキャン修飾子をamrescan
に渡すことができます。
amgettuple
関数はdirection
引数を持ちます。
これはForwardScanDirection
(通常の場合)またはBackwardScanDirection
のいずれかを取ることができます。
amrescan
後の最初の呼び出しがBackwardScanDirection
を指定していた場合、一致したインデックス項目は通常の前から後ろという方向ではなく、後ろから前という方向でスキャンされます。
そのため、amgettuple
は通常ならばインデックス内の最初に一致したタプルを返すところですが、最後に一致したタプルを返さなければなりません。
(これはamcanorder
が真に設定されたアクセスメソッドでのみ発生します。)
最初の呼び出しの後、amgettuple
は、最も最近に返された項目からどちらの方向にスキャンを進めるかを準備しなければなりません。
(しかしamcanbackward
が偽であれば、引き続くすべての呼び出しは最初のものと同じ方向を持ちます。)
順序付けされたスキャンを提供するアクセスメソッドはスキャン内位置の「記録」をサポートしなければならず、また、後でその記録された位置に戻ることをサポートしなければなりません。
同じ位置が複数回記録されるかもしれません。
しかし、スキャン内の1つの位置のみを記録する必要があります。
新しいammarkpos
呼び出しにより前回記録された位置は上書きされます。
順序付けされたスキャンをサポートしないアクセスメソッドはIndexAmRoutine
でammarkpos
関数およびamrestrpos
関数を提供する必要はないので、これらのポインタをNULLにセットしてください。
スキャン位置と記録された位置(もしあれば)の両方は、インデックス内の同時挿入や削除という観点における一貫性を保持しなければなりません。 スキャンが始まった時に存在していた場合、項目を見つけ出したスキャンが新しく挿入された項目を返さなかったとしても問題ありません。 このような場合のスキャンでは、再スキャンやバックアップによって、あたかも最初の時点で返されたものとして項目が返されます。 同様に、同時実行削除によってスキャンの結果に影響が出るかもしれません。 重要なことは、挿入や削除によって、その項目自体が挿入・削除されていない項目がスキャンで失われたり二重になったりすることが起こらないという点です。
インデックスが設定された列値がインデックスに格納されている(かつ、損失のある表現ではない)場合、ヒープタプルのTIDではなくインデックスに格納された実際のデータを返すインデックスオンリースキャンをサポートするのに有用です。 これは、可視性マップによってTIDが全可視のページ上にあると判断できる場合にI/Oを避けるだけのことです。 判断できない場合はMVCCを確認するためにヒープタプルにアクセスしなくてはなりません。 しかしその動作はアクセスメソッドでは考慮されていません。
amgettuple
を使用する代わりに、amgetbitmap
を使用して、一回の呼出しですべてのタプルを取り出してインデックススキャンを行うことができます。
これはアクセスメソッド内でのロック/ロック解除という過程を防ぐことができますので、amgettuple
よりもかなり効率的です。
実際には、amgetbitmap
はamgettuple
呼び出しを繰り返すことと同じ効果を持つはずですが、物事を単純化するために複数の制限を加えています。
まず第一に、amgetbitmap
は一回ですべてのタプルを返し、スキャン位置の記録と位置戻しをサポートしません。
第二に、特定の順序付けをまったく持たないビットマップの中にタプルが返されます。
これはamgetbitmap
がdirection
引数を取らない理由です。
(順序付け演算子はこのようなスキャンでは決して与えられません。)
また、amgetbitmap
によるインデックスオンリースキャンは提供されていません。なぜなら、インデックスタプルの内容を返す手段がないからです。
最後に、amgetbitmap
は返されたタプルに関し、62.4に記載した意味でのロックを保証しません。
アクセスメソッドの内部実装がどちらか片方のAPIにそぐわない場合、amgettuple
を実装せずamgetbitmap
のみを実装、またはその逆も許されていることに注意してください。