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

72.1. 概要 #

<title>Overview</title>

<productname>PostgreSQL</productname> includes an implementation of persistent on-disk hash indexes, which are fully crash recoverable. Any data type can be indexed by a hash index, including data types that do not have a well-defined linear ordering. Hash indexes store only the hash value of the data being indexed, thus there are no restrictions on the size of the data column being indexed. PostgreSQLには、クラッシュから完全に回復可能なディスク上の永続的なハッシュインデックスの実装が含まれています。 明確な線形順序付けを持たないものも含め、すべてのデータ型がハッシュインデックスでインデックス可能です。 ハッシュインデックスは、インデックスされる値のハッシュ値のみを保存するので、インデックス対象の列のサイズは制限となりません。

Hash indexes support only single-column indexes and do not allow uniqueness checking. ハッシュインデックスは単一列のインデックスのみをサポートし、唯一性のチェックはできません。

Hash indexes support only the <literal>=</literal> operator, so WHERE clauses that specify range operations will not be able to take advantage of hash indexes. ハッシュインデックスは=演算子のみをサポートしており、範囲演算を指定するWHERE句はハッシュインデックスの恩恵をこうむることができません。

Each hash index tuple stores just the 4-byte hash value, not the actual column value. As a result, hash indexes may be much smaller than B-trees when indexing longer data items such as UUIDs, URLs, etc. The absence of the column value also makes all hash index scans lossy. Hash indexes may take part in bitmap index scans and backward scans. 各インデックスタプルは単なる4バイトのハッシュ値で、実際の列の値ではありません。 そのため、UUIDやURLのような大きなデータをインデックスすると、ハッシュインデックスはB-treeよりもずっと小さくなるかも知れません。 また、列値が欠損しているとすべてのハッシュ走査が損失がある(lossy)ものになります。 ハッシュインデックスはビットマップインデックス走査と後方走査の一部となるかも知れません。

Hash indexes are best optimized for SELECT and UPDATE-heavy workloads that use equality scans on larger tables. In a B-tree index, searches must descend through the tree until the leaf page is found. In tables with millions of rows, this descent can increase access time to data. The equivalent of a leaf page in a hash index is referred to as a bucket page. In contrast, a hash index allows accessing the bucket pages directly, thereby potentially reducing index access time in larger tables. This reduction in "logical I/O" becomes even more pronounced on indexes/data larger than shared_buffers/RAM. ハッシュインデックスは、大きなテーブルに対して同値走査を使用するSELECTとUPDATEを多用するワークロードに対して最適です。 B-treeインデックスでは、走査はリーフページが見つかるまで木を降下しなければなりません。 何百万行のテーブルではこの降下走査によりデータをアクセスする時間がかかることがあります。 対照的に、ハッシュインデックスはバケットページを直接アクセスすることが可能で、大きなテーブルでのインデックスアクセスの時間を短縮できる可能性があります。 「論理的なI/O」における時間短縮は、共有バッファ/RAMよりもインデックス/データが大きな時にはより顕著になります。

Hash indexes have been designed to cope with uneven distributions of hash values. Direct access to the bucket pages works well if the hash values are evenly distributed. When inserts mean that the bucket page becomes full, additional overflow pages are chained to that specific bucket page, locally expanding the storage for index tuples that match that hash value. When scanning a hash bucket during queries, we need to scan through all of the overflow pages. Thus an unbalanced hash index might actually be worse than a B-tree in terms of number of block accesses required, for some data. ハッシュインデックスはハッシュ値の均等ではない分布を想定して設計されています。 バケットページへのアクセスはハッシュ値が均一に分布している時にうまく働きます。 挿入によりバケットページが満杯になると、追加の溢れページが特定のパケットページに連結され、そのハッシュ値に適合するインデックスタプル用の領域を局所的に拡張します。 問い合わせ中にハッシュバケットを走査する際は、すべての溢れページを走査する必要があります。 ですからバランスの崩れたハッシュインデックスは、あるデータに対してはアクセスしなければならないブロックの数という意味では、Bツリーよりも悪いかも知れません。

As a result of the overflow cases, we can say that hash indexes are most suitable for unique, nearly unique data or data with a low number of rows per hash bucket. One possible way to avoid problems is to exclude highly non-unique values from the index using a partial index condition, but this may not be suitable in many cases. 溢れ出が出るケースを考慮すると、ハッシュインデックスは一意か、ほぼ一意に近いデータあるいは、それぞれのハッシュバケットに少数の行があるデータがもっとも適していると言えます。 問題を避けることができる可能性のある方法として、部分インデックス条件を使って極端に一意ではない値を排除する方法がありますが、多くの場合にこれが適しているとは言えないかも知れません。

Like B-Trees, hash indexes perform simple index tuple deletion. This is a deferred maintenance operation that deletes index tuples that are known to be safe to delete (those whose item identifier's LP_DEAD bit is already set). If an insert finds no space is available on a page we try to avoid creating a new overflow page by attempting to remove dead index tuples. Removal cannot occur if the page is pinned at that time. Deletion of dead index pointers also occurs during VACUUM. Bツリーのように、ハッシュインデックスは単純なインデックスタプルの削除を行います。 これは削除しても安全であると分かるインデックスタプル(アイテム識別子のLP_DEADビットがすでにセットされている)を削除する遅延操作です。 挿入の際にページに領域が見つからない場合は、不要インデックスタプルを削除することによって、新しい溢れページを作成するのを回避しようとします。 その時点でそのページにピンがある場合は削除することはできません。 不要インデックスポインタの削除もVACUUM中に発生します。

If it can, VACUUM will also try to squeeze the index tuples onto as few overflow pages as possible, minimizing the overflow chain. If an overflow page becomes empty, overflow pages can be recycled for reuse in other buckets, though we never return them to the operating system. There is currently no provision to shrink a hash index, other than by rebuilding it with REINDEX. There is no provision for reducing the number of buckets, either. 可能ならば、VACUUMはインデックスタプルをできるだけ少ない溢れページに押し込むことも試みます。 ある溢れページが空になったらその溢れページは再利用できますが、オペレーティングシステムに返却することはありません。 今の所、REINDEXで再構築する以外にハッシュインデックスを縮小するようにする予定はありません。 バケット数を少なくする予定もありません。

Hash indexes may expand the number of bucket pages as the number of rows indexed grows. The hash key-to-bucket-number mapping is chosen so that the index can be incrementally expanded. When a new bucket is to be added to the index, exactly one existing bucket will need to be "split", with some of its tuples being transferred to the new bucket according to the updated key-to-bucket-number mapping. ハッシュインデックスはインデックスされた行数が増えるとバケットページ数も拡張します。 ハッシュキーからバケット番号へのマッピングは、インデックスが徐々に拡張できるように選択されます。 新しいバケットがインデックスに追加されることになったら、存在しているバケットの厳密に一つが「分割」される必要があります。 更新されたハッシュキーからバケット番号へのマッピングにしたがって、タプルが新しいバケットに転送されます。

The expansion occurs in the foreground, which could increase execution time for user inserts. Thus, hash indexes may not be suitable for tables with rapidly increasing number of rows. その拡張はフォアグラウンドで行われるので、ユーザが挿入を実行するのにかかる時間を増加させるでしょう。 ですから、ハッシュインデックスは行数が急激に拡張するテーブルには適していないかもしれません。