2013-04-18 7 views
3

У меня есть небольшая база данных PostgreSQL (~ ~ 3000 строк).PostgreSQL Поиск по всему тексту: почему поиск медленнее?

Я пытаюсь настроить полнотекстовый поиск в одном из его текстовых полей («тело»).

Проблема в том, что любой запрос выполняется очень медленно (35+ секунд !!!).

Я полагаю, что проблема возникает из-за того, что DB выбирает режим последовательного сканирования ...

Это мой запрос:

SELECT 
     ts_rank_cd(to_tsvector('italian', body), query), 
     ts_headline('italian', body, to_tsquery('torino')), 
     title, 
     location, 
     id_author 
    FROM 
     fulltextsearch.documents, to_tsquery('torino') as query 
    WHERE 
     (body_tsvector @@ query) 
    OFFSET 
     0 

Это EXPLAIN ANALYZE:

         QUERY PLAN          
---------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=0.00..1129.81 rows=19 width=468) (actual time=74.059..13630.114 rows=863 loops=1) 
-> Nested Loop (cost=0.00..1129.81 rows=19 width=468) (actual time=74.056..13629.342 rows=863 loops=1) 
    Join Filter: (documents.body_tsvector @@ query.query) 
    -> Function Scan on to_tsquery query (cost=0.00..0.01 rows=1 width=32) (actual time=4.606..4.608 rows=1 loops=1) 
    -> Seq Scan on documents (cost=0.00..1082.09 rows=3809 width=591) (actual time=0.045..48.072 rows=3809 loops=1) 
Total runtime: 13630.720 ms 

Это моя таблица:

mydb=# \d+ fulltextsearch.documents; 
               Table "fulltextsearch.documents" 
    Column  |  Type  |        Modifiers        | Storage | Description 
---------------+-------------------+-----------------------------------------------------------------------+----------+------------- 
id   | integer   | not null default nextval('fulltextsearch.documents_id_seq'::regclass) | plain | 
id_author  | integer   |                  | plain | 
body   | character varying |                  | extended | 
title   | character varying |                  | extended | 
location  | character varying |                  | extended | 
date_creation | date    |                  | plain | 
body_tsvector | tsvector   |                  | extended | 
Indexes: 
    "fulltextsearch_documents_tsvector_idx" gin (to_tsvector('italian'::regconfig,  COALESCE(body, ''::character varying)::text)) 
    "id_idx" btree (id) 
Triggers: 
    body_tsvectorupdate BEFORE INSERT OR UPDATE ON fulltextsearch.documents FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('body_tsvector', 'pg_catalog.italian', 'body') 
Has OIDs: no 

Я уверен, что мне не хватает чего-то очевидного ....

Любые подсказки?

.

.

.

=== ОБНОВЛЕНИЕ =========================================================== ==========================================

Благодаря вашим предложениям я придумал этот (лучший) запрос:

SELECT 
    ts_rank(body_tsvector, query), 
    ts_headline('italian', body, query), 
    title, 
    location 
FROM 
    fulltextsearch.documents, to_tsquery('italian', 'torino') as query 
WHERE 
    to_tsvector('italian', coalesce(body,'')) @@ query 

, который является довольно хорошим, но всегда очень медленным (13+ секунд ...).

Я замечаю, что комментируя строку «ts_headline()», запрос является молниеносным.

Это EXPLAIN ANALYZE, который, наконец, использует индекс, но не поможет мне много ...:

EXPLAIN ANALYZE SELECT 
clock_timestamp() - statement_timestamp() as elapsed_time, 
    ts_rank(body_tsvector, query), 
    ts_headline('italian', body, query), 
    title, 
    location 
FROM 
    fulltextsearch.documents, to_tsquery('italian', 'torino') as query 
WHERE 
    to_tsvector('italian', coalesce(body,'')) @@ query 

Nested Loop (cost=16.15..85.04 rows=19 width=605) (actual time=102.290..13392.161 rows=863 loops=1) 
    -> Function Scan on query (cost=0.00..0.01 rows=1 width=32) (actual time=0.008..0.009 rows=1 loops=1) 
    -> Bitmap Heap Scan on documents (cost=16.15..84.65 rows=19 width=573) (actual time=0.381..4.236 rows=863 loops=1) 
     Recheck Cond: (to_tsvector('italian'::regconfig, (COALESCE(body, ''::character varying))::text) @@ query.query) 
     -> Bitmap Index Scan on fulltextsearch_documents_tsvector_idx (cost=0.00..16.15 rows=19 width=0) (actual time=0.312..0.312 rows=863 loops=1) 
       Index Cond: (to_tsvector('italian'::regconfig, (COALESCE(body, ''::character varying))::text) @@ query.query) 
Total runtime: 13392.717 ms 

ответ

4

Вы недостающие два (достаточно очевидных) вещей:

1 Вы установили 'italian' в свой , но вы не указали его в to_tsquery()

Храните оба согласованных.

2 Вы указали COALESCE(body, ...), но это не то, что вы ищете.

Планировщик не является магическим - вы можете использовать только индекс, если это то, что вы ищете.

+2

Планировщик прост и консервативен в выборе индекса. Он не будет искать язык tsearch2 по умолчанию, чтобы узнать, является ли это 'italian', а затем обрабатывает версию, не определенную языком, так же, как и язык-указана-как-итальянская версия, для того чтобы оба вызова функций были * одинаковыми *. Фактически, в этом отношении планировщик может быть немного тусклым - в прошлый раз, когда я проверил, было довольно много простых вариаций в отношении того, как вы могли бы написать выражение - например, резервные скобки - это привело бы к тому, что планировщик не узнал, что он соответствует индексу , –

+0

@Richard Huxton Спасибо за ваш ответ. Под «поиском против» вы имеете в виду предложение FROM? Если да, не могли бы вы разместить образец правильного предложения FROM для моей ситуации? Извините, я все еще довольно смущен ... – MarcoS

+1

http://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-HEADLINE «ts_headline использует исходный документ, а не сводку tsvector, поэтому он может быть медленным и должен использоваться с осторожностью ... » –

0

Наконец, с помощью ваших ответов и комментариев, а также с некоторыми поисковыми системами, я решил решить, выполнив ts_headline() (очень тяжелая функция, я полагаю) на подмножестве полного набора результатов (страница результатов Я заинтересован в):

SELECT 
     id, 
     ts_headline('italian', body, to_tsquery('italian', 'torino')) as headline, 
     rank, 
     title, 
     location 
    FROM (
     SELECT 
      id, 
      body, 
      title, 
      location, 
      ts_rank(body_tsvector, query) as rank 
     FROM 
      fulltextsearch.documents, to_tsquery('italian', 'torino') as query 
     WHERE 
      to_tsvector('italian', coalesce(body,'')) @@ query 
     LIMIT 10 
     OFFSET 0 
    ) as s 
0

Я решил проблему, предварительно рассчитав в ts_rank_cd и хранить его в таблице для популярных терминов (частых) в корпусе. Поиск просматривает эту таблицу, чтобы получить отсортированный рейтинг doc для запроса. если нет (для менее популярных терминов), он по умолчанию будет создавать ts_rank_cd на лету.

Пожалуйста, взгляните на это сообщение.

https://dba.stackexchange.com/a/149701

Смежные вопросы