Eu tenho uma tabela que contém dados extraídos de documentos de texto. Os dados são armazenados em uma coluna chamada "CONTENT"para a qual eu criei esse índice usando o GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Eu uso a seguinte consulta para executar uma pesquisa de texto completo na tabela:
SELECT "ITEMID",
ts_rank(setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C') ,
plainto_tsquery('english', 'searchTerm')) AS "RANK"
FROM "File"
WHERE setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C')
@@ plainto_tsquery('english', 'searchTerm')
ORDER BY "RANK" DESC
LIMIT 5;
A tabela Arquivo contém 250 000 linhas e cada "CONTENT"entrada consiste em uma palavra aleatória e uma sequência de texto que é igual para todas as linhas.
Agora, quando procuro uma palavra aleatória (1 acerto na tabela inteira), a consulta é executada muito rapidamente (<100 ms). No entanto, quando procuro uma palavra que esteja presente em todas as linhas, a consulta é extremamente lenta (10 minutos ou mais).
EXPLAIN ANALYZEmostra que, para a pesquisa de um clique, é realizada uma verificação de índice de bitmap seguida de uma verificação de heap de bitmap . Para a pesquisa lenta, é realizada uma Seq Scan , que é o que está demorando tanto.
Concedido, não é realista ter os mesmos dados em todas as linhas. Mas como não consigo controlar os documentos de texto enviados pelos usuários, nem as pesquisas que eles realizam, é possível que ocorra um cenário semelhante (pesquise termos com ocorrência muito alta no DB). Como posso aumentar o desempenho da minha consulta de pesquisa para esse cenário?
Executando o PostgreSQL 9.3.4
Planos de consulta de EXPLAIN ANALYZE:
Pesquisa rápida (1 hit no DB)
"Limit (cost=2802.89..2802.90 rows=5 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" -> Sort (cost=2802.89..2806.15 rows=1305 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''wfecg'''::tsquery))"
" Sort Method: quicksort Memory: 25kB"
" -> Bitmap Heap Scan on "File" (cost=38.12..2781.21 rows=1305 width=26) (actual time=0.030..0.031 rows=1 loops=1)"
" Recheck Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
" -> Bitmap Index Scan on "File_contentIndex" (cost=0.00..37.79 rows=1305 width=0) (actual time=0.012..0.012 rows=1 loops=1)"
" Index Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
"Total runtime: 0.069 ms"
Pesquisa lenta (250k ocorrências no banco de dados)
"Limit (cost=14876.82..14876.84 rows=5 width=26) (actual time=519667.404..519667.405 rows=5 loops=1)"
" -> Sort (cost=14876.82..15529.37 rows=261017 width=26) (actual time=519667.402..519667.402 rows=5 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''cyberspace'''::tsquery))"
" Sort Method: top-N heapsort Memory: 25kB"
" -> Seq Scan on "File" (cost=0.00..10541.43 rows=261017 width=26) (actual time=2.097..519465.953 rows=261011 loops=1)"
" Filter: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''cyberspace'''::tsquery)"
" Rows Removed by Filter: 6"
"Total runtime: 519667.429 ms"
explain (analyze, buffers), de preferência com track_io_timing definido como ON? Não há como levar 520 segundos para verificar seq essa tabela, a menos que você a armazene em um RAID de disquetes. Algo é definitivamente patológico lá. Além disso, qual é a sua configuração random_page_coste os outros parâmetros de custo?
ORDER BY "RANK" DESC. Eu investigariapg_trgmcom o índice GiST e os operadores de similaridade / distância como alternativa. Considere: dba.stackexchange.com/questions/56224/… . Pode até produzir resultados "melhores" (além de serem mais rápidos).