Ho una tabella che contiene dati estratti da documenti di testo. I dati sono memorizzati in una colonna chiamata "CONTENT"
per la quale ho creato questo indice usando GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Uso la seguente query per eseguire una ricerca di testo completo sulla tabella:
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 tabella File contiene 250.000 righe e ogni "CONTENT"
voce è composta da una parola casuale e una stringa di testo uguale per tutte le righe.
Ora, quando cerco una parola casuale (1 hit nell'intera tabella) la query viene eseguita molto velocemente (<100 ms). Tuttavia, quando cerco una parola presente in tutte le righe, la query è estremamente lenta (10 minuti o più).
EXPLAIN ANALYZE
mostra che per la ricerca a 1 hit viene eseguita una Scansione indice bitmap seguita da una scansione heap bitmap . Per la ricerca lenta viene invece eseguita una scansione Seq , che è ciò che richiede così tanto tempo.
Certo, non è realistico avere gli stessi dati in tutte le righe. Ma dal momento che non riesco a controllare i documenti di testo che vengono caricati dagli utenti, né le ricerche che eseguono, è possibile che si verifichi uno scenario simile (ricerca di termini con ricorrenza molto elevata nel DB). Come posso aumentare le prestazioni della mia query di ricerca per un tale scenario?
Esecuzione di PostgreSQL 9.3.4
Piani di query da EXPLAIN ANALYZE
:
Ricerca rapida (1 hit nel 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"
Ricerca lenta (250.000 risultati nel 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)
, preferibilmente con track_io_timing impostato su ON
? Non è necessario impiegare 520 secondi per eseguire la scansione di tale tabella, a meno che non sia memorizzato su un RAID di floppy disk. Qualcosa è decisamente patologico lì. Inoltre, qual è la tua impostazione random_page_cost
e gli altri parametri di costo?
ORDER BY "RANK" DESC
. Vorrei investigarepg_trgm
con indice GiST e gli operatori somiglianza / a distanza come alternativa. Considerare: dba.stackexchange.com/questions/56224/… . Potrebbe anche produrre risultati "migliori" (oltre ad essere più veloce).