バージョンごとのドキュメント一覧

64.4. インデックスのロック処理に関する検討 #

<title>Index Locking Considerations</title>

Index access methods must handle concurrent updates of the index by multiple processes. The core <productname>PostgreSQL</productname> system obtains <literal>AccessShareLock</literal> on the index during an index scan, and <literal>RowExclusiveLock</literal> when updating the index (including plain <command>VACUUM</command>). Since these lock types do not conflict, the access method is responsible for handling any fine-grained locking it might need. An <literal>ACCESS EXCLUSIVE</literal> lock on the index as a whole will be taken only during index creation, destruction, or <command>REINDEX</command> (<literal>SHARE UPDATE EXCLUSIVE</literal> is taken instead with <literal>CONCURRENTLY</literal>). インデックスアクセスメソッドは、複数のプロセスによるインデックスの同時更新を取り扱えなければなりません。 PostgreSQLコアシステムはインデックススキャン中にインデックスに対してAccessShareLockを獲得します。 また、(通常のVACUUMを含む)インデックスの更新中にRowExclusiveLockを獲得します。 これらの種類のロックは競合しませんので、アクセスメソッドは必要になるかもしれない粒度の細かなロック処理に関して責任を持ちます。 インデックスの生成、破棄、REINDEX時にインデックス全体に対するACCESS EXCLUSIVEロックが獲得されます(CONCURRENTLYでは代わりにSHARE UPDATE EXCLUSIVEが取得されます)。

Building an index type that supports concurrent updates usually requires extensive and subtle analysis of the required behavior. For the b-tree and hash index types, you can read about the design decisions involved in <filename>src/backend/access/nbtree/README</filename> and <filename>src/backend/access/hash/README</filename>. 同時更新をサポートするインデックス種類を構築することは通常、必要な動作について広範かつ微細にわたる解析が必要です。 B-treeおよびハッシュインデックス種類では、src/backend/access/nbtree/READMEsrc/backend/access/hash/READMEにある設計に関する決定事項を読むことができます。

Aside from the index's own internal consistency requirements, concurrent updates create issues about consistency between the parent table (the <firstterm>heap</firstterm>) and the index. Because <productname>PostgreSQL</productname> separates accesses and updates of the heap from those of the index, there are windows in which the index might be inconsistent with the heap. We handle this problem with the following rules: インデックス自身の内部的な一貫性要求の他に、同時実行更新には、親テーブル(ヒープ)とインデックス間の一貫性に関する問題が発生します。 PostgreSQLはヒープへのアクセスおよび更新とインデックスへのアクセスおよび更新を分離していますので、インデックスとヒープとの間の一貫性が無くなる間隔が存在します。 以下の規則でこうした問題を扱います。

Without the third rule, it is possible for an index reader to see an index entry just before it is removed by <command>VACUUM</command>, and then to arrive at the corresponding heap entry after that was removed by <command>VACUUM</command>. This creates no serious problems if that item number is still unused when the reader reaches it, since an empty item slot will be ignored by <function>heap_fetch()</function>. But what if a third backend has already re-used the item slot for something else? When using an MVCC-compliant snapshot, there is no problem because the new occupant of the slot is certain to be too new to pass the snapshot test. However, with a non-MVCC-compliant snapshot (such as <literal>SnapshotAny</literal>), it would be possible to accept and return a row that does not in fact match the scan keys. We could defend against this scenario by requiring the scan keys to be rechecked against the heap row in all cases, but that is too expensive. Instead, we use a pin on an index page as a proxy to indicate that the reader might still be <quote>in flight</quote> from the index entry to the matching heap entry. Making <function>ambulkdelete</function> block on such a pin ensures that <command>VACUUM</command> cannot delete the heap entry before the reader is done with it. This solution costs little in run time, and adds blocking overhead only in the rare cases where there actually is a conflict. 3番目の規則がないと、VACUUMによって削除される直前に、インデックス読み取りがインデックス項目を見つけ、そして、VACUUMによって削除された後に対応するヒープ項目に達する可能性があります。 空の項目スロットはheap_fetch()で無視されますので、これは読み取りが達した時にその項目番号が未使用である場合でも大きな問題は起こりません。 しかし、第三のバックエンドがすでにその項目スロットを他のものに再使用した場合はどうなるでしょうか? そのスロット内の新しいものが、スナップショット試験を通過するには新しすぎることが確実ですので、MVCCに則ったスナップショットを使用する場合は問題ありません。 しかし、MVCCに則らないスナップショット(SnapshotAnyなど)では、実際にはスキャンキーに合わない行を受付け、返す可能性があります。 すべての場合においてヒープ行に対しスキャンキーの再検査を行うことを必須とすることで、こうした状況から保護することができますが、これは高価すぎます。 代わりに、読み取りがまだ一致するヒープ項目へのインデックス項目の作業中であることを示す代理として、インデックスページに対するピンを使用します。 このピンに対してambulkdeleteがブロックするようにすることで、読み取りの作業が終わる前にVACUUMがそのヒープ項目を削除できないことを確実にします。 実行時におけるこの対策のコストは小さく、実際に競合が発生するごく稀な場合にのみブロックするためのオーバーヘッドが加わります。

This solution requires that index scans be <quote>synchronous</quote>: we have to fetch each heap tuple immediately after scanning the corresponding index entry. This is expensive for a number of reasons. An <quote>asynchronous</quote> scan in which we collect many TIDs from the index, and only visit the heap tuples sometime later, requires much less index locking overhead and can allow a more efficient heap access pattern. Per the above analysis, we must use the synchronous approach for non-MVCC-compliant snapshots, but an asynchronous scan is workable for a query using an MVCC snapshot. この対策は、インデックススキャンが同期していることを要求します。 対応するインデックス項目のスキャンの後即座に各ヒープタプルを取り出さなければなりません。 多くの理由のため、これは高価です。 インデックスから多くのTIDを収集し、少し後でのみヒープタプルにアクセスする非同期スキャンでは、必要なロック処理オーバーヘッドがかなり少なくなり、また、より効率的なヒープへのアクセスパターンを取ることができます。 上の解析に従うと、MVCCに則らないスナップショットでは同期方式を使用しなければなりませんが、問い合わせがMVCCスナップショットを使用する場合は非同期スキャンを使用することができます。

In an <function>amgetbitmap</function> index scan, the access method does not keep an index pin on any of the returned tuples. Therefore it is only safe to use such scans with MVCC-compliant snapshots. amgetbitmapインデックススキャンでは、アクセスメソッドは返されるタプル上にインデックスピンをまったく保持しません。 したがって、MVCCに則ったスナップショットでこうしたスキャンを使用することのみが安全です。

When the <structfield>ampredlocks</structfield> flag is not set, any scan using that index access method within a serializable transaction will acquire a nonblocking predicate lock on the full index. This will generate a read-write conflict with the insert of any tuple into that index by a concurrent serializable transaction. If certain patterns of read-write conflicts are detected among a set of concurrent serializable transactions, one of those transactions may be canceled to protect data integrity. When the flag is set, it indicates that the index access method implements finer-grained predicate locking, which will tend to reduce the frequency of such transaction cancellations. ampredlocksフラグが設定されていない場合、シリアライザブルトランザクション内でそのインデックスアクセスメソッドを使用するスキャンはいずれもインデックス全体に対するブロックしない述語ロックを獲得します。 これは、同時実行のシリアライザブルトランザクションによるそのインデックスへの何らかのタプル挿入で、読み書きの競合が発生することがあります。 同時実行のシリアライザブルトランザクションの集合の中で特定の読み書きの競合パターンが検知された場合、データの整合性を保護するためにこれらのトランザクションの1つはキャンセルされます。 このフラグが設定されている場合、こうしたトランザクションのキャンセルの頻度を低減することになる、より粒度の細かな述語ロックをインデックスアクセスメソッドが実装していることを示します。