2011-02-09 33 views
5

タイプがの列にの列にインデックスを作成することは可能です。 GINインデックスを使って試してみました。しかし、クエリはこれらのインデックスを使用していないようです。PostgreSQLの文字列配列のインデックス配列

Example 

CREATE TABLE users (
name VARCHAR(100), 
groups text[], 
); 

Query: SELECT name FROM users WHERE ANY(groups) = 'Engineering'. 

また、それは「グループ」を与えると数えることができるように効率的に「グループ」列にGROUP BYを実行するための最良の方法は何ですか。

+3

正規化を妨げる原因は何ですか? –

+0

実際のテーブルには、複数の複数の値を持つカラムがあります。 Dbはパフォーマンスが低下するため、過度の結合を避けたいと考えていたこれらの列に対して、比較的正規化されています。私が使用した 'User'テーブルは単なる例です。 – Anoop

答えて

2

GINインデックスを使用することができる。

CREATE TABLE users (
name VARCHAR(100), 
groups text[] 
); 

CREATE INDEX idx_users ON users USING GIN(groups); 

-- disable sequential scan in this test: 
SET enable_seqscan TO off; 

EXPLAIN ANALYZE 
SELECT name FROM users WHERE groups @> (ARRAY['Engineering']); 

結果:

"Bitmap Heap Scan on users (cost=4.26..8.27 rows=1 width=218) (actual time=0.021..0.021 rows=0 loops=1)" 
" Recheck Cond: (groups @> '{Engineering}'::text[])" 
" -> Bitmap Index Scan on idx_users (cost=0.00..4.26 rows=1 width=0) (actual time=0.016..0.016 rows=0 loops=1)" 
"  Index Cond: (groups @> '{Engineering}'::text[])" 
"Total runtime: 0.074 ms" 

は別の問題となるアレイ上に集計関数を使用します。関数unnest()が役に立ちます。

データを正規化してみませんか?それはあなたがまだエンパワーしなかった多くの問題を含む、すべての問題を修正します。

+0

ARRAY ['Engineering']をクエリに使用しなかったと思います。その結果、GINインデックスは決して使用されませんでした。正規化に関して、実際のテーブルとユースケースは私が言及したものとは異なります。実際のテーブルには、文字列の配列を使って表現された複数の列があります。私はテーブルあたりの予想レコード数が何百万というオーダーであるため、複数の結合を避けようとしていました。 – Anoop

+0

私は演算子@>すべての違いを作ると思う、それはANY()のように見えるインデックスを使用することはできません。 –

+0

具体的には、大きな中間テーブルや結果テーブルが必要な場合は、できるだけDBMSがアクセスできるようにデータを作成する必要があります。正規化では、値を扱ういくつかのケースで参照を扱うことができます。 –

0

これを処理する最善の方法は、モデルを正規化することだと思います。私はそれを試していないので、おそらくエラーが含まれていますが、そのアイデアは明確でなければなりません:

CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR(100) UNIQUE); 
CREATE TABLE groups (id INTEGER PRIMARY KEY, name VARCHAR(100) UNIQUE); 
CREATE TABLE user_group (
    user INTEGER NOT NULL REFERENCES users, 
    group INTEGER NOT NULL REFERENCES groups); 
CREATE UNIQUE INDEX user_group_unique ON user_group (user, group); 

SELECT users.name 
    FROM user_group 
    INNER JOIN users ON user_group.user = users.id 
    INNER JOIN groups ON user_group.group = groups.id 
    WHERE groups.name = 'Engineering'; 

実行計画はかなり効率的です。特定のグループのメンバーを見つけるためにsequential_scanではなくindex_scanを使用できるようにするには、user_group(group)を索引付けしても最適化できます。

+0

この特定のユースケースの正規化を避けたかったのです。そのため、私は文字列データ型の配列を使用することが強制されました。 – Anoop