Как оптимизировать мою базу данных PostgreSQL для поиска префиксов? - PullRequest
3 голосов
/ 15 июня 2010

У меня есть таблица, называемая "узлами" с примерно 1,7 миллионами строк в моей базе данных PostgreSQL

=#\d nodes
            Table "public.nodes"
 Column |          Type          | Modifiers 
--------+------------------------+-----------
 id     | integer                | not null
 title  | character varying(256) | 
 score  | double precision       | 
Indexes:
    "nodes_pkey" PRIMARY KEY, btree (id)

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

=# explain analyze select title,score from nodes where title ilike 's%' order by score desc; 
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
 Sort  (cost=64177.92..64581.38 rows=161385 width=25) (actual time=4930.334..5047.321 rows=161264 loops=1)
   Sort Key: score
   Sort Method:  external merge  Disk: 5712kB
   ->  Seq Scan on nodes  (cost=0.00..46630.50 rows=161385 width=25) (actual time=0.611..4464.413 rows=161264 loops=1)
         Filter: ((title)::text ~~* 's%'::text)
 Total runtime: 5260.791 ms
(6 rows)

Это было слишком медленно, чтобы использовать его с автозаполнением.С некоторой информацией из Использование PostgreSQL в приложениях Web 2.0 Мне удалось улучшить это с помощью специального индекса

=# create index title_idx on nodes using btree(lower(title) text_pattern_ops);
=# explain analyze select title,score from nodes where lower(title) like lower('s%') order by score desc limit 10;
                                                                QUERY PLAN                                                                
------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=18122.41..18122.43 rows=10 width=25) (actual time=1324.703..1324.708 rows=10 loops=1)
   ->  Sort  (cost=18122.41..18144.60 rows=8876 width=25) (actual time=1324.700..1324.702 rows=10 loops=1)
         Sort Key: score
         Sort Method:  top-N heapsort  Memory: 17kB
         ->  Bitmap Heap Scan on nodes  (cost=243.53..17930.60 rows=8876 width=25) (actual time=96.124..1227.203 rows=161264 loops=1)
               Filter: (lower((title)::text) ~~ 's%'::text)
               ->  Bitmap Index Scan on title_idx  (cost=0.00..241.31 rows=8876 width=0) (actual time=90.059..90.059 rows=161264 loops=1)
                     Index Cond: ((lower((title)::text) ~>=~ 's'::text) AND (lower((title)::text) ~<~ 't'::text))
 Total runtime: 1325.085 ms
(9 rows)

Так что это дало мне ускорение в 4 раза. Но может ли это быть и дальше?улучшенный?Что если я хочу использовать '%s%' вместо 's%'?Есть ли у меня хоть какой-нибудь шанс получить приличную производительность с PostgreSQL?Или мне лучше попробовать другое решение (Lucene ?, Sphinx?) Для реализации функции автозаполнения?

Ответы [ 3 ]

4 голосов
/ 14 августа 2013

Вам понадобится индекс text_pattern_ops, если вы не находитесь в локали C.

См .: типы индексов .

2 голосов
/ 15 июня 2010

Советы для дальнейшего изучения:

  • Разделите таблицу по ключу заголовка.Это делает списки меньшими, с чем нужно работать postgres.

  • дают postgresql больше памяти, поэтому частота обращений в кэш> 98%.Эта таблица займет около 0.5G, я думаю, что 2G в настоящее время не должно быть проблемой.Убедитесь, что сбор статистики включен и считан в таблицах pg_stats.

  • Создайте вторую таблицу с уменьшенным заголовком заголовка, например, 12 символов, чтобы полная таблица помещалась в меньшем количестве блоков базы данных.Индекс подстроки также может работать, но требует тщательного запроса.

  • Чем длиннее подстрока, тем быстрее будет выполняться запрос.Создайте отдельную таблицу для небольших подстрок и сохраните в качестве значения первую десятку или любой из вариантов, которые вы хотели бы показать.Существует около 20000 комбинаций из 1,2,3 символьных строк.

  • Вы можете использовать ту же идею, если хотите получать запросы% abc%, но, вероятно, переключение на lucene имеет смысл сейчас.

0 голосов
/ 15 июня 2010

Вас явно не интересуют 150000+ результатов, поэтому вы должны ограничить их:

select title,score
  from nodes
  where title ilike 's%'
  order by score desc
  limit 10;

Вы также можете рассмотреть возможность создания функционального индекса и использования "> =" и "<": </p>

create index nodes_title_lower_idx on nodes (lower(title));
select title,score
  from nodes
  where lower(title)>='s' and lower(title)<'t'
  order by score desc
  limit 10;

Вы также должны создать индекс на счет, который поможет в случае ilike %s%.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...