Tengo una tabla que contiene datos que se extraen de documentos de texto. Los datos se almacenan en una columna llamada "CONTENT"
para la cual he creado este índice usando GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Utilizo la siguiente consulta para realizar una búsqueda de texto completo en la tabla:
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;
La tabla Archivo contiene 250 000 filas y cada "CONTENT"
entrada consta de una palabra aleatoria y una cadena de texto que es igual para todas las filas.
Ahora, cuando busco una palabra aleatoria (1 hit en toda la tabla) la consulta se ejecuta muy rápido (<100 ms). Sin embargo, cuando busco una palabra que está presente en todas las filas, la consulta se ejecuta extremadamente lenta (10 minutos o más).
EXPLAIN ANALYZE
muestra que para la búsqueda de 1 acierto se realiza un Análisis de índice de mapa de bits seguido de un Análisis de montón de mapa de bits . Para la búsqueda lenta, se realiza un Seq Scan , que es lo que lleva tanto tiempo.
Por supuesto, no es realista tener los mismos datos en todas las filas. Pero dado que no puedo controlar los documentos de texto que cargan los usuarios, ni las búsquedas que realizan, es posible que surja un escenario similar (buscar términos con una ocurrencia muy alta en DB). ¿Cómo puedo aumentar el rendimiento de mi consulta de búsqueda para tal escenario?
Ejecutar PostgreSQL 9.3.4
Consultar planes de EXPLAIN ANALYZE
:
Búsqueda rápida (1 acierto en 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"
Búsqueda lenta (250k hits en DB)
"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)
, preferiblemente con track_io_timing establecido en ON
? No hay forma de que se tarde 520 segundos en explorar esa tabla, a menos que la tenga almacenada en un RAID de disquetes. Algo es definitivamente patológico allí. Además, ¿cuál es su configuración random_page_cost
y los otros parámetros de costo?
ORDER BY "RANK" DESC
. Investigaríapg_trgm
con el índice GiST y los operadores de similitud / distancia como alternativa. Considere: dba.stackexchange.com/questions/56224/… . Incluso podría producir "mejores" resultados (además de ser más rápido).