49.3. インデックススキャン

インデックススキャンでは、スキャンキーに一致するものと示したすべてのタプルの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における前処理の必要性は、 インデックスアクセスメソッドがスキャンキーを"正規化"形式にする必要があるかどうかに依存します。

amgettuple関数はdirection引数を持ちます。 ForwardScanDirection(通常の場合)またはBackwardScanDirectionのいずれかを取ることができます。 amrescan後の最初の呼び出しがBackwardScanDirectionを指定していた場合、 一致したインデックス項目は通常の前から後ろという方向ではなく、後ろから前という方向でスキャンされます。 そのため、amgettupleは 通常ならばインデックス内の最初に一致したタプルを返すところですが、最後に一致したタプルを返さなければなりません。 (これは、pg_am.amorderstrategyを非0に設定することで順序付きスキャンをサポートするものと広告されたアクセスメソッドでのみ発生します。) 最初の呼び出しの後、amgettupleは、最も最近に返された項目からどちらの方向にスキャンを進めるかを準備しなければなりません。

アクセスメソッドはスキャン内位置の"記録"をサポートしなければならず、また、後でその記録された位置に戻ることをサポートしなければなりません。 同じ位置が複数回記録されるかもしれません。 しかし、スキャン内の1つの位置のみを記録する必要があります。 新しいammarkpos呼び出しにより前回記録された位置は上書きされます。

スキャン位置と記録された位置(もしあれば)の両方は、インデックス内の同時挿入や削除という観点における一貫性を保持しなければなりません。 スキャンが始まった時に存在していた場合、項目を見つけ出したスキャンが新しく挿入された項目を返さなかったとしても問題ありません。 このような場合のスキャンでは、再スキャンやバックアップによって、あたかも最初の時点で返されたものとして項目が返されます。 同様に、同時実行削除によってスキャンの結果に影響が出るかもしれません。 重要なことは、挿入や削除によってスキャンが返す項目において、その項目自体が挿入・削除されていない項目が失われたり二重になったりすることが起こらないという点です。

amgettupleを使用する代わりに、amgetmultiを使用して呼出し毎に複数タプルを取り出してインデックススキャンを行うことができます。 これはアクセスメソッド内でのロック・ロック解除という過程を防ぐことができますので、amgettupleよりもかなり効率的です。 実際には、amgetmultiamgettuple呼び出しを繰り返すことと同じ効果を持つはずですが、単純化するために複数の制限を加えています。 まず、amgetmultidirection引数を取りません。 そのため、これは後方方向へのスキャンや方向を内部で反転させるスキャンをサポートしません。 またamgetmultiの間、アクセスメソッドは位置の記録や位置の復旧をサポートする必要はありません。 (amgetmultiスキャンでこれらの機能を使用することは困難で、呼び出し元のバッファされたリストを複雑にしますので、これらの制限はコストを少なくします。) 最後に、amgetmulti は返されたタプルに関し、項49.4に記載した意味でのロックを保証しません。