タイプinteger
の外部キー_other_id
_を持つ大きなテーブル(6億行)があります。外部キーの単一の値は、平均で約100回繰り返されます。データは_other_id
_によって頻繁に選択されるため、そのFK列にインデックスが必要です。
私のテストでは、gin
インデックスタイプはデフォルトのbtree
インデックスよりも約10倍小さく、約3倍パフォーマンスが高いことが示されています(パフォーマンスはSELECT
クエリを使用してテストされました)。
問題は、gin
インデックスの代わりにbtree
インデックスを使用することの現実的な欠点があるかどうかです。このインデックスタイプは、私のような非常に一般的なケース、つまりinteger
外部キーではあまり使用されていないようです。しかし、私のテストでは、パフォーマンスが大幅に向上しています。なぜそのようなシナリオではgin
が推奨されないのですか?
gin
列にinteger
インデックスを使用できるようにするには、_CREATE EXTENSION btree_gin
_を実行する必要がありました。
UPDATE
がデフォルトで有効になっているためにFASTUPDATE
が遅くなる可能性があることを知っています: 時折/断続的、遅い(10秒以上)PostgreSQLのUPDATEクエリGINインデックス付きのテーブル
同等の_=
_演算子がインデックスを使用できることだけに関心があります(また、値の数が多すぎる可能性があるIN (...)
ですが、これも同等であることを前提としています)。
これはかなり難解なことのように思われます。これがおそらく、あまり推奨されない理由です。問題が発生したときにお勧めしますが、それほど頻繁ではありません。 1つのインデックスのサイズは、データベース全体のコンテキストではそれほど意味がありません。そのため、通常、インデックスを小さくしても、それほど心配する必要はありません。
これが外部キーであることに特有の欠点はないと思います。制約の多値側を維持するために使用される自動生成クエリは、Btreeインデックスだけでなく、GINインデックスも使用できます。
必要なことを示す関連するベンチマークを行わない限り、「fastupdate」をオフにします。インデックスは「btree_gin」を使用するスカラーを超えているため、通常のGINインデックスの場合のように、挿入された各行のインデックスページ書き込みが急激に増えることはないため、fastupdateの必要性は少なくなります。
このインデックスタイプは通常のbtreeインデックスよりも使用頻度が低いため、発見されていないバグが潜んでいる可能性が高くなります(特にfastpdate = onの場合)。それが本当に価値のあるものを提供するのであれば、私はそれを使用するのをやめさせません(そしてしないでください)が、私が考えられるあらゆる場所で単に「btree_gin」を盲目的に使用することを防ぎます。
私が気づいたことの1つは、GINインデックスへの更新/挿入の再生が(私が単純に期待していたものと比較して)かなり遅いように見えることです。これは、PITR、回復、またはストリーミングレプリケーションに関連する可能性があります。それらのいずれかがあなたにとって重要である場合、それらをテストに含めてください。
必要な拡張子はbtree_gin
ではなくpg_trgm
。
最大の欠点は、GINインデックスの更新がBツリーインデックスよりも遅いことです(そのため、fastupdate
オプションが発明されました)。
データの変更がほとんどなく、クエリ速度がより重要であるため、それで問題ない場合は、GINインデックスを使用します(ただし、クエリを遅くする可能性があるため、fastupdate
を無効にすることをお勧めします)。
データの変更速度をベンチマークして、それがどのように機能するかを把握することができます。
ginインデックスタイプは、デフォルトのbtreeインデックスよりも約10倍小さく、パフォーマンスは約3倍です(パフォーマンスはSELECTクエリを使用してテストされました)。
そして:
btreeは30 GB、ginは3 GBです。
はい、それはGINインデックスを支持してひどく話します。
OTOH、これ:
平均して約100回繰り返しました。
この:
Other_id列は更新しないと思いますが、多くの行を挿入できます。また、同じother_id値を設定する行に対してUPDATEステートメントを発行する場合もあります。
other_id
に関して、または少なくとも同じother_id
のクラスターで、テーブルの多くが物理的にソートされていることを示しているようです。もしそうなら、そして/またはあなたはあまりにも多くの行を順不同で更新せず、other_id
でソートされた言及した「多くの行」を挿入することができ、そして/または時々テーブルをCLUSTER
する余裕があります(またはpg_repack
で同じことを行って、同時書き込みアクセスを許可します)、次に block range index(BRIN) を検討します。 ずっと小さくなりますが、
CREATE INDEX tbl_other_id_brin_idx ON tbl USING brin (other_id)
マニュアル:
pages_per_range
BRINインデックスのエントリごとに1つのブロック範囲を構成するテーブルブロックの数を定義します(詳細は セクション67.1 を参照)。デフォルトは
128
です。
あなたの場合、次のように、より小さなpages_per_range
設定を試してみるとよいでしょう。
CREATE INDEX tbl_other_id_brin_idx ON tbl USING brin (other_id)
WITH (pages_per_range = 8);
この設定、およびインデックスのサイズとパフォーマンスは、物理的なクラスタリング、行サイズ、書き込みパターン、および一般的なクエリに大きく依存します。通常はBツリーインデックスよりも低速ですが、ケースに応じてうまくいく場合があります。
関連: