У меня есть таблица, которая содержит данные, извлеченные из текстовых документов. Данные хранятся в столбце, "CONTENT"
для которого я создал этот индекс, используя GIN:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
Я использую следующий запрос для выполнения полнотекстового поиска в таблице:
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;
Таблица File содержит 250 000 строк, и каждая "CONTENT"
запись состоит из одного случайного слова и текстовой строки, которая одинакова для всех строк.
Теперь, когда я ищу случайное слово (1 попадание во всей таблице), запрос выполняется очень быстро (<100 мс). Однако, когда я ищу слово, которое присутствует во всех строках, запрос выполняется очень медленно (10 минут и более).
EXPLAIN ANALYZE
показывает, что для поиска с 1 попаданием выполняется сканирование индекса растрового изображения, а затем сканирование кучи растрового изображения . Для медленного поиска вместо этого выполняется Seq Scan , что занимает так много времени.
Конечно, нереально иметь одинаковые данные во всех строках. Но так как я не могу контролировать текстовые документы, загружаемые пользователями, и поиск, который они выполняют, возможно, возникает подобный сценарий (поиск по терминам с очень высокой частотой в БД). Как я могу увеличить производительность моего поискового запроса для такого сценария?
Запуск PostgreSQL 9.3.4
Планы запроса от EXPLAIN ANALYZE
:
Быстрый поиск (1 попадание в БД)
"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"
Медленный поиск (250 тыс. Просмотров в БД)
"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)
, предпочтительно с track_io_timing, установленным в ON
? Нет никакого способа, которым может потребоваться 520 секунд для последующего сканирования этой таблицы, если только она не хранится на RAID-диске с гибкими дисками. Там что-то определенно патологическое. Кроме того, каковы ваши настройки random_page_cost
и другие параметры стоимости?
ORDER BY "RANK" DESC
. Я хотел бы исследоватьpg_trgm
с индексом GiST и операторов сходства / расстояния в качестве альтернативы. Рассмотрим: dba.stackexchange.com/questions/56224/… . Может даже привести к «лучшим» результатам (помимо того, что быстрее).