Ich habe eine Tabelle, die Daten enthält, die aus Textdokumenten extrahiert werden. Die Daten werden in einer Spalte gespeichert, "CONTENT"
für die ich diesen Index mit GIN erstellt habe:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Ich verwende die folgende Abfrage, um eine Volltextsuche für die Tabelle durchzuführen:
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;
Die Dateitabelle enthält 250 000 Zeilen und jeder "CONTENT"
Eintrag besteht aus einem zufälligen Wort und einer Textzeichenfolge, die für alle Zeilen gleich ist.
Wenn ich jetzt nach einem zufälligen Wort suche (1 Treffer in der gesamten Tabelle), wird die Abfrage sehr schnell ausgeführt (<100 ms). Wenn ich jedoch nach einem Wort suche, das in allen Zeilen vorhanden ist, wird die Abfrage extrem langsam ausgeführt (10 Minuten oder länger).
EXPLAIN ANALYZE
zeigt, dass für die 1-Treffer-Suche ein Bitmap-Index-Scan gefolgt von einem Bitmap-Heap-Scan durchgeführt wird. Für die langsame Suche wird stattdessen ein Seq-Scan durchgeführt, was so lange dauert.
Zugegeben, es ist nicht realistisch, in allen Zeilen dieselben Daten zu haben. Da ich jedoch weder die von den Benutzern hochgeladenen Textdokumente noch die von ihnen durchgeführten Suchvorgänge steuern kann, tritt möglicherweise ein ähnliches Szenario auf (Suche nach Begriffen mit sehr hohem Vorkommen in der Datenbank). Wie kann ich die Leistung meiner Suchanfrage für ein solches Szenario steigern?
Ausführen von PostgreSQL 9.3.4
Abfragepläne von EXPLAIN ANALYZE
:
Schnellsuche (1 Treffer in 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"
Langsame Suche (250.000 Treffer in der 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)
, vorzugsweise mit track_io_timing auf ON
? Es sollte auf keinen Fall 520 Sekunden dauern, bis diese Tabelle gescannt wurde, es sei denn, Sie haben sie auf einem RAID von Disketten gespeichert. Dort ist definitiv etwas pathologisch. Was ist Ihre Einstellung random_page_cost
und die anderen Kostenparameter?
ORDER BY "RANK" DESC
. Ich würdepg_trgm
mit dem GiST-Index und den Ähnlichkeits- / Distanzoperatoren als Alternative untersuchen. Bedenken Sie: dba.stackexchange.com/questions/56224/… . Könnte sogar "bessere" Ergebnisse liefern (außer schneller zu sein).