2011-02-09 17 views
5

È possibile creare un indice su una colonna il cui tipo è array di stringhe. Provato usando gli indici GIN . Ma le query non sembrano utilizzare quegli indici.Indicizzazione dell'array del tipo di colonna di stringhe in PostgreSql

Example 

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

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

anche qual è il modo migliore per eseguire GROUP BY sulla colonna 'gruppi' in modo efficiente in modo che possa dare 'gruppi' e contare.

+3

Cosa impedisce la normalizzazione? –

+0

La tabella effettiva ha più colonne multivalore. Db è relativamente normalizzato, aspettarsi per queste colonne in cui volevo evitare i join eccessivi in ​​quanto sta rallentando le prestazioni. La tabella "Utente" che ho usato è solo un esempio. – Anoop

risposta

2

Un indice gin possono essere utilizzati:

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']); 

risultati:

"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" 

Utilizzando le funzioni di aggregazione su una matrice, che sarà un altro problema. La funzione unnest() potrebbe essere d'aiuto.

Perché non si normalizzano i dati? Ciò risolverà tutti i problemi, compresi molti problemi che non hai ancora incontrato.

+0

Penso di non aver usato ARRAY ['Engineering'] nella query e come risultato l'indice GIN non è mai stato utilizzato. Per quanto riguarda la normalizzazione, la tabella effettiva e il caso d'uso sono diversi da quelli che ho menzionato. La tabella effettiva ha più colonne multivalore rappresentate utilizzando una serie di stringhe. Stavo cercando di evitare più join in quanto il numero previsto di record per tabella è dell'ordine di milioni. – Anoop

+0

Penso che l'operatore @> faccia la differenza, sembra che ANY() non possa usare l'indice. –

+0

In particolare quando si prevedono tabelle intermedie e/o di risultati di grandi dimensioni, è necessario rendere i dati accessibili al DBMS il più possibile. La normalizzazione consente di lavorare con un riferimento in diversi casi in cui altrimenti lavoreresti con valori. –

0

Penso che il modo migliore per gestire questo sarebbe normalizzare il modello. Di seguito sarà probabilmente contiene errori come io non l'ho provato, ma l'idea deve essere chiaro:

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'; 

Il piano di esecuzione risultante dovrebbe essere abbastanza efficace già; è possibile ottimizzare ancora indicizzando ON user_group (group), che consente a index_scan piuttosto che a sequential_scan di trovare i membri di un particolare gruppo.

+0

Volevo evitare la normalizzazione per questo particolare caso d'uso. Questo è il motivo per cui sono stato costretto a usare array di tipo di dati di stringhe. – Anoop

Problemi correlati