インデックスの最大行サイズエラー


12

array列に上限はありますか?

配列フィールドに挿入すると、このエラーが発生します-

PG::Error: ERROR:  index row size 3480 exceeds maximum 2712 for index "ix_data"

これが私のテーブル定義です-

create table test_array(id varchar(50), data text[]);

ALTER TABLE test_array ADD PRIMARY KEY (id);

CREATE INDEX ix_data ON test_array USING GIN (data);

配列フィールドを検索しているので、配列フィールドにインデックスが必要です。


それはそれは可能性がありdata、この中で示されたようにタグのリストが含まれているスコット・スナイダーによる関連ブログの記事?それが事実なら、私はあなたのためのより良い解決策を持っているかもしれません。
Erwin Brandstetter 2012

user310525、そこにアカウントを作成し、モデレーターに移行のフラグを立てる意思がある場合、dba.seのほうがよいというErwinの提案の2番目にしたいと思います。
ジャックは、topanswers.xyzを試してみると12

回答:


14

問題

これは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追加の演算子と演算子クラスを提供する拡張に興味があるかもしれません。

sqlfiddleの完全に機能するライブデモ。


2

エラーはフィールドix_dataではなく、インデックスにありtext[]ます。特定のインデックスタイプの行の最大サイズは2712バイトに制限されています。インデックスを削除して挿入を再試行すると、うまくいくはずです。より大きなフィールドにインデックスを付ける必要がある場合は、postgresの全文インデックス付け機能を調べてください。


2

これはPostGIS地理カラムで取得していました。誤ってインデックスを作成してしまったからです。このようなインデックスを作成する場合は、USING GISTパラメータを含める必要があります。


ありがとう-以上でした!うわー、これまでにフェッチ。時間を節約できたかもしれません。特にデフォルトでGiSTが使われていると思っていたのですが、間違ってb-treeを使おうとしました。
ジョナス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.