O problema
Aqui está um caso muito semelhante discutido no pgsql.general . É sobre a limitação em um índice de árvore b, mas é o mesmo porque um índice GIN usa um índice de árvore b internamente para chaves e, portanto, é executado na mesma limitação para o tamanho da chave (em vez do tamanho do item em uma árvore b simples índice).
Cito o manual sobre a implementação do índice GIN :
Internamente, um índice GIN contém um índice de árvore B construído sobre chaves, em que cada chave é um elemento de um ou mais itens indexados
De qualquer forma, pelo menos um elemento da matriz em sua coluna data
é muito grande para ser indexado. Se esse for apenas um valor estranho ou algum tipo de acidente, você poderá truncar o valor e concluir o processo.
Para os fins da seguinte demonstração, assumirei o contrário: muitos valores de texto longo na matriz.
Solução simples
Você pode substituir elementos em sua matriz data
por valores de hash correspondentes . E envie valores de pesquisa através da mesma função hash. Obviamente, você provavelmente deseja armazenar seus originais em algum lugar. Com isso, quase chegamos à minha segunda variante ...
Solução avançada
Você pode criar uma tabela de consulta para elementos de matriz com uma serial
coluna como chave primária substituta (efetivamente um tipo radical de valor de hash) - o que é ainda mais interessante se os valores dos elementos envolvidos não forem exclusivos:
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
Como queremos procurar elem
, adicionamos um índice - mas um índice a uma expressão dessa vez, com apenas os 10 primeiros caracteres do texto longo. Isso deve ser suficiente na maioria dos casos para restringir uma pesquisa a um ou alguns hits. Adapte o tamanho à sua distribuição de dados. Ou use uma função hash mais sofisticada.
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
Sua coluna data
seria do tipo int[]
. Renomeei a mesa data
e me livrei do sinistro que varchar(50)
você tinha no seu exemplo:
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
Cada elemento da matriz data
refere-se a a elem.elem_id
. Nesse ponto, você pode considerar substituir a coluna da matriz por uma tabela n: m, normalizando assim seu esquema e permitindo que o Postgres imponha integridade referencial. A indexação e o manuseio geral se tornam mais fáceis ...
No entanto, por razões de desempenho, a int[]
coluna em combinação com um índice GIN pode ser superior. O tamanho do armazenamento é muito menor. Nesse caso, precisamos do índice GIN:
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
Agora, cada chave do índice GIN (= elemento da matriz) é um em integer
vez de um longo text
. O índice será menor em várias ordens de magnitude; as pesquisas, consequentemente, serão muito mais rápidas.
A desvantagem: antes que você possa realmente fazer uma pesquisa, é necessário procurar elem_id
na tabela elem
. Usar o meu índice funcional recém-introduzido elem_elem_left10_idx
também será muito mais rápido.
Você pode fazer tudo isso em uma consulta simples :
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
Você pode estar interessado na extensão intarray
, que fornece operadores e classes de operadores adicionais.
data
contém uma lista de tags como demonstradas nesta postagem de blog relacionada por Scott Snyder ? Se for esse o caso, talvez eu tenha uma solução melhor para você.