★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

52.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における前処理の必要性は、インデックスアクセスメソッドがスキャンキーを"正規化"形式にする必要があるかどうかに依存します。

一部のアクセスメソッドは、他では行いませんが、十分に定義された順序でインデックス項目を返します。 アクセスメソッドが出力の順序付けをサポートできるようにする方法は、実質2種類存在します。

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

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

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

インデックスが設定された列値がインデックスに格納されている(かつ、不可逆表現ではない)場合、ヒープタプルのTIDではなくインデックスに格納された実際のデータを返すindex-only scansをサポートするのに有用です。 これは、可視性マップによって可視化されたページ上のTIDが判断できる場合にのみ動作します。判断できない場合はMVCCを確認するためにヒープタプルにアクセスしなくてはなりません。 しかしその動作はアクセスメソッドでは考慮されていません。

amgettupleを使用する代わりに、amgetbitmapを使用して、一回の呼出しですべてのタプルを取り出してインデックススキャンを行うことができます。 これはアクセスメソッド内でのロック/ロック解除という過程を防ぐことができますので、amgettupleよりもかなり効率的です。 実際には、amgetbitmapamgettuple呼び出しを繰り返すことと同じ効果を持つはずですが、物事を単純化するために複数の制限を加えています。 まず第一に、amgetbitmapは一回ですべてのタプルを返し、スキャン位置の記録と位置戻しをサポートしません。 第二に、特定の順序付けをまったく持たないビットマップの中にタプルが返されます。 これはamgetbitmapdirection引数を取らない理由です。 (順序付け演算子はこのようなスキャンでは決して与えられません。) また、amgetbitmapによるインデックスオンリースキャンは提供されていません。なぜなら、インデックスタプルの内容を返す手段がないからです。 最後に、amgetbitmapは返されたタプルに関し、項52.4に記載した意味でのロックを保証しません。

アクセスメソッドの内部実装がどちらか片方のAPIにそぐわない場合、amgettupleを実装せずamgetbitmapのみを実装、またはその逆も許されていることに注意してください。