Optimization 如何为前缀搜索优化我的PostgreSQL数据库?
我有一个名为nodes的表,在我的PostgreSQL数据库中大约有170万行Optimization 如何为前缀搜索优化我的PostgreSQL数据库?,optimization,postgresql,autocomplete,Optimization,Postgresql,Autocomplete,我有一个名为nodes的表,在我的PostgreSQL数据库中大约有170万行 =#\d nodes Table "public.nodes" Column | Type | Modifiers --------+------------------------+----------- id | integer | not null title | character varying(25
=#\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)
这对于将其与自动完成一起使用是非常缓慢的。有了来自我的一些信息,我能够通过一个特殊的索引来改进这一点
=# 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?要实现我的自动完成功能?进一步调查的提示: 在标题键上对表进行分区。这使得postgres需要处理的列表更小 为postgresql提供更多内存,使缓存命中率>98%。这张桌子大约需要0.5克,我想现在2克应该没问题了。确保已启用统计数据收集并读取pg_统计表 制作第二个表,减少标题的字串,例如12个字符,以使整个表适合更少的数据库块。子字符串上的索引也可以工作,但需要仔细查询 子字符串越长,查询运行的速度就越快。为小的子字符串创建一个单独的表,并将前十个或任何您想要显示的选项存储在值中。大约有20000个1、2、3个字符串的组合 如果您希望有%abc%的查询,您可以使用相同的想法,但是现在切换到lucene可能是有意义的
您显然对150000+个结果不感兴趣,因此您应该限制它们:
select title,score
from nodes
where title ilike 's%'
order by score desc
limit 10;
你也可以考虑创建函数索引,如果你不在C语言环境中,使用>=和你需要一个TeXOpTypnnopsindex。
请参阅: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;