web-dev-qa-db-ja.com

整数の外部キーにGIN PostgreSQLインデックスを使用することの欠点はありますか?

タイプ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 (...)ですが、これも同等であることを前提としています)。

3

これはかなり難解なことのように思われます。これがおそらく、あまり推奨されない理由です。問題が発生したときにお勧めしますが、それほど頻繁ではありません。 1つのインデックスのサイズは、データベース全体のコンテキストではそれほど意味がありません。そのため、通常、インデックスを小さくしても、それほど心配する必要はありません。

これが外部キーであることに特有の欠点はないと思います。制約の多値側を維持するために使用される自動生成クエリは、Btreeインデックスだけでなく、GINインデックスも使用できます。

必要なことを示す関連するベンチマークを行わない限り、「fastupdate」をオフにします。インデックスは「btree_gin」を使用するスカラーを超えているため、通常のGINインデックスの場合のように、挿入された各行のインデックスページ書き込みが急激に増えることはないため、fastupdateの必要性は少なくなります。

このインデックスタイプは通常のbtreeインデックスよりも使用頻度が低いため、発見されていないバグが潜んでいる可能性が高くなります(特にfastpdate = onの場合)。それが本当に価値のあるものを提供するのであれば、私はそれを使用するのをやめさせません(そしてしないでください)が、私が考えられるあらゆる場所で単に「btree_gin」を盲目的に使用することを防ぎます。

私が気づいたことの1つは、GINインデックスへの更新/挿入の再生が(私が単純に期待していたものと比較して)かなり遅いように見えることです。これは、PITR、回復、またはストリーミングレプリケーションに関連する可能性があります。それらのいずれかがあなたにとって重要である場合、それらをテストに含めてください。

3
jjanes

必要な拡張子はbtree_ginではなくpg_trgm

最大の欠点は、GINインデックスの更新がBツリーインデックスよりも遅いことです(そのため、fastupdateオプションが発明されました)。

データの変更がほとんどなく、クエリ速度がより重要であるため、それで問題ない場合は、GINインデックスを使用します(ただし、クエリを遅くする可能性があるため、fastupdateを無効にすることをお勧めします)。

データの変更速度をベンチマークして、それがどのように機能するかを把握することができます。

2
Laurenz Albe

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ツリーインデックスよりも低速ですが、ケースに応じてうまくいく場合があります。

関連:

2