У меня есть таблица, называемая "узлами" с примерно 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?) Для реализации функции автозаполнения?