問題
これはpgsql.generalで議論された非常に類似したケースです。それはbツリーインデックスの制限についてですが、GINインデックスは内部的にキーに bツリーインデックスを使用するため、(通常のbツリーのアイテムサイズではなく)キーサイズに同じ制限が適用されるため、すべて同じですインデックス)。
GINインデックスの実装に関するマニュアルを引用します。
内部的には、GINインデックスにはキー上に構築されたBツリーインデックスが含まれ、各キーは1つ以上のインデックス付きアイテムの要素です
いずれの場合も、列内の少なくとも1つの配列要素data
が大きすぎてインデックスを作成できません。これが唯一の異常な値または何らかの事故の場合は、値を切り捨てて処理できる可能性があります。
次のデモの目的のために、私はそれ以外の場合を想定します:配列内の多くの長いテキスト値。
シンプルなソリューション
配列内の要素data
を対応するハッシュ値で置き換えることができます。そして、同じハッシュ関数を介してルックアップ値を送信します。もちろん、オリジナルをさらにどこかに保存したいと思うでしょう。これで、2番目のバリアントに到着します...
高度なソリューション
serial
代理主キー(事実上、根本的な種類のハッシュ値)として列を含む配列要素のルックアップテーブルを作成できます。これは、関係する要素の値が一意でない場合にさらに興味深いものになります。
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
検索したいのでelem
、インデックスを追加します。ただし、今回は式のインデックスで、長いテキストの最初の10文字のみを使用します。これで、ほとんどの場合、検索を1つまたはいくつかのヒットに絞り込むことができます。サイズをデータ分布に適合させます。または、より高度なハッシュ関数を使用します。
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
data
その場合、列のタイプはになりint[]
ます。私はテーブルの名前をに変更し、あなたの例にあっdata
た不吉なものvarchar(50)
を取り除きました:
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
の各配列要素はをdata
参照しますelem.elem_id
。この時点で、配列列をn:mテーブルに置き換えることを検討してください。これにより、スキーマが正規化され、Postgresが参照整合性を適用できるようになります。インデックス作成と一般的な処理が簡単になります...
ただし、パフォーマンス上の理由から、int[]
GINインデックスと組み合わせた列の方が優れている場合があります。収納サイズはずっと小さいです。この場合、GINインデックスが必要です。
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
現在、GINインデックス(=配列要素)の各キーinteger
は、長めのの代わりにtext
です。インデックスは数桁小さくなり、結果として検索がはるかに速くなります。
欠点:実際に検索を実行する前にelem_id
、テーブルからを検索する必要がありますelem
。私が新しく導入した関数型インデックスを使用するとelem_elem_left10_idx
、これもはるかに高速になります。
すべてを1つの単純なクエリで実行できます。
SELECT d.*, e.*
FROM elem e
JOIN data d ON ARRAY[e.elem_id] <@ d.data
WHERE left(e.elem, 10) = left('word1234word', 10) -- match index condition
AND e.elem = 'word1234word'; -- need to recheck, functional index is lossy
intarray
追加の演算子と演算子クラスを提供する拡張に興味があるかもしれません。
data
、この中で示されたようにタグのリストが含まれているスコット・スナイダーによる関連ブログの記事?それが事実なら、私はあなたのためのより良い解決策を持っているかもしれません。