12.9. GiSTおよびGINインデックス種類

全文検索を高速化するために、2種類のインデックスが使えます。全文検索のためにインデックスが必須だと言うわけではないことを言っておかなければなりませんが、日常的に検索される列には、インデックスを使った方が良いでしょう。

       CREATE INDEX name ON table USING gist(column);
      

GiST (Generalized Search Tree)インデックスを作ります。columntsvector またはtsquery 型です。

       CREATE INDEX name ON table USING gin(column);
      

GIN (Generalized Inverted Index)インデックスを作ります。 columntsvector型でなけれ ばなりません。

この2つのインデックス形式には、性能上の大きな違いがあります。ですので、それらの特長を理解しておくことが重要です.

GiSTインデックスは、非可逆です。つまり、インデックスは間違った結果を返すかも知れないので、間違った結果を排除するために、テーブルの行をチェックすることが必要です。PostgreSQLはこの処理が必要とされた時に自動的に行います。 GiSTインデックスが非可逆なのは、インデックス中の各文書が固定長の署名によって表現されているからです。署名は、各々の単語をハッシュして単一なビットにして、これらのビットをnビットの文書署名にORし、nビットの列中のビットにすることで実現されています。2つの単語が同じビット位置を生成すると、間違った一致が起こります。問い合わせ対象のすべての単語が照合すると(それが正しいか間違っているかは別として)、その照合が正しいものかどうかテーブルの行を取得して調べなければなりません。

非可逆性は、間違った照合によるテーブルからの不必要なデータ取得のため、性能を劣化させます。テーブルへのランダムアクセスは遅いので、GiSTインデックスの有用性は制限されています。誤った照合がどの位あるかという可能性はいくつか要因によりますが、とりわけユニークな単語の数に依存します。ですから、辞書を使ってユニークな単語の数を減らすことをお勧めします。

GINインデックスは標準の問い合わせに対しては非可逆ではありませんが、その性能はユニークな単語の数の対数に依存します。(しかしながら、GINインデックスはtsvector値の中の単語(語彙素)のみを保持しており、重み付けラベルは持っていません。したがって、重み付けを伴う問合わせではテーブルの行を再チェックしなければなりません。)

GiST、GINのどちらのインデックス形式を選ぶにあたっては、以下の性能上の違いを考慮してください。

大雑把に言うと、GINインデックスは検索が高速なので、静的なデータにもっとも向いています。動的なデータには、GiSTインデックスの更新が高速です。とりわけ、GiSTインデックスは、動的なデータに非常に向いており、ユニークな単語(語彙素)が100,000未満ならば高速です。一方GINインデックスは100,000以上の語彙素をよりうまく扱うことができますが、更新が遅いです。

GINインデックスの構築時間はmaintenance_work_memを増やすことによってしばしば改善することができることに注意してください。一方GiSTインデックスの構築時間にはあまりそのパラメータは効きません。

大きなデータをパーティショニングし、GiST、GINインデックスを使うことによってオンラインの更新を伴いながら、非常に高速な検索を実現することができます。パーティショニングは、継承を使ってデータベースレベルで実現できます。あるいは、文書を複数のサーバに分散させ、contrib/dblink拡張モジュールを使って検索結果を集約できます。これは、ランキング関数がローカルな情報しか使わないために可能になります。