PostgreSQLは配列の列にインデックスを付けることができますか?


144

ドキュメントでこの質問に対する明確な答えを見つけることができません。列が配列型の場合、入力されたすべての値に個別にインデックスが付けられますか?

1つのint[]列を持つ単純なテーブルを作成し、そのテーブルに一意のインデックスを配置しました。同じintの配列を追加できないことに気づきました。これは、インデックスが各項目のインデックスではなく、配列項目の複合であると私に思わせます。

INSERT INTO "Test"."Test" VALUES ('{10, 15, 20}');
INSERT INTO "Test"."Test" VALUES ('{10, 20, 30}');

SELECT * FROM "Test"."Test" WHERE 20 = ANY ("Column1");

インデックスはこのクエリに役立ちますか?


データ型jsonbとインデックスを使用することは可能ですか?postgresql.org/docs/9.5/static/functions-json.htmlおよびpostgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXING
user3791372

回答:


181

はい、配列にインデックスを付けることができますが、配列演算子GINインデックスタイプを使用する必要があります。

例:

    CREATE TABLE "Test"("Column1" int[]);
    INSERT INTO "Test" VALUES ('{10, 15, 20}');
    INSERT INTO "Test" VALUES ('{10, 20, 30}');

    CREATE INDEX idx_test on "Test" USING GIN ("Column1");

    -- To enforce index usage because we have only 2 records for this test... 
    SET enable_seqscan TO off;

    EXPLAIN ANALYZE
    SELECT * FROM "Test" WHERE "Column1" @> ARRAY[20];

結果:

Bitmap Heap Scan on "Test"  (cost=4.26..8.27 rows=1 width=32) (actual time=0.014..0.015 rows=2 loops=1)
  Recheck Cond: ("Column1" @> '{20}'::integer[])
  ->  Bitmap Index Scan on idx_test  (cost=0.00..4.26 rows=1 width=0) (actual time=0.009..0.009 rows=2 loops=1)
        Index Cond: ("Column1" @> '{20}'::integer[])
Total runtime: 0.062 ms
注意

多くの場合、gin__int_opsオプションが必要であるようです

create index <index_name> on <table_name> using GIN (<column> gin__int_ops)

gin__int_opsオプションなしで&&および@>演算子で動作するケースはまだ見ていません


19
OPが推測するように、これは実際には個々の配列値にインデックスを付けるのではなく、配列全体にインデックスを付けます。したがって、これは問題のクエリに役立ちますが(説明プランを参照)、個々の配列値に一意の制約を(簡単に)作成することはできません。つまり、整数配列を使用している場合は、contribモジュール「intarray」を使用して個々の配列値にインデックスを付けることができます。これにより、多くの場合、はるかに高速になります。(IIRCでは、テキスト値についてこれに関していくつかの作業が行われていますが、貢献者はおそらくそれを完了するのを手伝ってくれるでしょう)。
xzilla

15
コード例のPostgreSQL識別子に大文字を使用しないでください。引用符/大文字の折りたたみ規則に慣れていない人、特にPostgreSQLを初めて使用する人を混乱させるだけです。
intgr 2015年

6
ここで私のコメントを繰り返します。私の経験から、これらのインデックスは、列に使用しない限り、 ほとんどまたはまったくスピードアップしません。このopクラスを発見するまで、私は何年も欲求不満と他の解決策を探していました。それは境界線の奇跡の労働者です。gin__int_opsinteger[]
IamIC 2017年

1
@IamICは、文字列の配列にインデックスを付ける必要がないことを意味しますか?そして、私は整数配列だけにインデックスを付けるべきですか?
ryan2johnson9

93

@Tregoregは彼の提供された賞金へのコメントで質問を提起しました:

現在の回答が機能しているとは思いませんでした。配列型の列でGINインデックスを使用しても、ANY()演算子のパフォーマンスは向上しません。本当に解決策はありませんか?

@Frankの受け入れられた答えは、配列演算子を使用するように指示しています。これは、Postgres 11 でも正しいです。マニュアル:

... PostgreSQLの標準ディストリビューションには、配列用のGIN演算子クラスが含まれており、これらの演算子を使用したインデックス付きクエリをサポートしています。

<@
@>
=
&&

標準ディストリビューションのGINインデックスの組み込み演算子クラスの完全なリストはこちらです。

Postgresでは、インデックスは演算子(特定のタイプに実装されています)にバインドされています。これは、Postgresの元のバークレーデザインの遺産であり、現在変更するのは非常に困難です。そして、それは一般的にうまく機能しています。これはpgsql-bugsのスレッドで、Tom Laneがこれについてコメントしています。

一部のPostGis 関数(などST_DWithin())はこの原則に違反しているようですが、そうではありません。これらの関数は、それぞれの演算子を使用するように内部的に書き換えられます。

インデックス付きの式は、演算子の左側にある必要があります。ほとんどの演算子(上記のすべてを含む)では、a COMMUTATORが定義されている場合、インデックス付きの式を右に配置すると、クエリプランナーはオペランドを反転することでこれを実現できます。ANY構築物は、種々の演算子と組み合わせて使用すると、オペレータ自体ではないことができます。配列要素constant = ANY (array_expression)=演算子をサポートするインデックスのみとして使用する場合は適格であり、= ANY()ます。GINインデックスは公開されていません。

Postgresは現在、GINでインデックス可能な式をそこから導出するほど賢くありません。手始めに、constant = ANY (array_expression)ある完全に同等ではないarray_expression @> ARRAY[constant]。NULL 要素が含まれている場合、配列演算子はエラーを返しますが、ANY構造体はどちらの側でもNULLを処理できます。また、データ型の不一致の結果は異なります。

関連する回答:

アサイド

協力しながらinteger配列int4、ないint2か、int8なし)NULLの値(あなたの例が示すように)追加のモジュールを検討intarray専門、より高速な演算子とインデックスのサポートを提供し、。見る:

UNIQUE未回答の質問の制約については、それは配列全体(疑わしいように)のbtreeインデックスで実装されており、要素の検索にはまったく役立ちません。詳細:


1
あぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁでぃででしょですが、理論的には可能だとしてもpostgresがインデックスをつけないなんて思いもしませんでした。たぶん、インデックスが演算子にバインドされているなど、postgresに対する私の洞察力の欠如が原因かもしれません。私の不適切な質問に答えて、あなたの知識を共有してくれてありがとう!
Tregoreg 2015年

6
@Tregoreg:恥ずかしがらないでください。はっきりしすぎていません。私が最初にそれに遭遇したとき、私はこれに自分で混乱したことを覚えています。追加された質問と説明は、一般の人々にとって非常に役立つはずです。
Erwin Brandstetter 2015年

1
私の経験から、これらのインデックスは、列に使用しない限り、 ほとんどまたはまったく高速化されません。このopクラスを発見するまで、私は何年も欲求不満と他の解決策を探していました。それは境界線の奇跡の労働者です。gin__int_opsinteger[]
IamIC 2017年

2
@IamIC:intarrayへのポインターを追加しました。あなたが指摘したように、注目に値するようです。
Erwin Brandstetter

ANY (array_expression) = constant表現、GINインデックスは罰金を動作しますか?
user10375

37

個々の配列要素にインデックスを付けることができるようになりました。例えば:

CREATE TABLE test (foo int[]);
INSERT INTO test VALUES ('{1,2,3}');
INSERT INTO test VALUES ('{4,5,6}');
CREATE INDEX test_index on test ((foo[1]));
SET enable_seqscan TO off;

EXPLAIN ANALYZE SELECT * from test WHERE foo[1]=1;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Scan using test_index on test  (cost=0.00..8.27 rows=1 width=32) (actual   time=0.070..0.071 rows=1 loops=1)
   Index Cond: (foo[1] = 1)
 Total runtime: 0.112 ms
(3 rows)

これは少なくともPostgres 9.2.1で動作します。配列のインデックスごとに個別のインデックスを作成する必要があることに注意してください。この例では、最初の要素にのみインデックスを付けました。


28
失われないようにしてください。このアプローチは、ANY()演算子を使用する可変長配列には絶望的です。
Καrτhικ

24
これはあまり役に立ちません。配列要素の数が決まっている場合は、配列項目ごとに高価な式インデックスを作成する代わりに、要素ごとに個別の列(およびプレーンなbtreeインデックス)を使用します。個々の列のストレージは、配列のオーバーヘッドがないため、はるかに安価です。
Erwin Brandstetter 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.