我有一个名为“nodes”的表,我的PostgreSQL数据库中有大约170万行
=#\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)
使用自动完成功能时,这很慢。通过Using PostgreSQL in Web 2.0 Applications中的一些信息,我可以使用特殊索引
来改善这一点=# 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?)来实现我的自动完成功能?
答案 0 :(得分:4)
如果您不在text_pattern_ops
区域设置,则需要C
索引。
请参阅:index types。
答案 1 :(得分:2)
进一步调查的提示:
在标题键上对表进行分区。这使得postgres需要使用的列表更小。
给postgresql更多内存,所以缓存命中率&gt; 98%。这个表大约需要0.5G,我认为现在2G应该没问题。确保启用统计信息收集并在pg_stats表中读取。
制作第二个表格,其中包含标题的缩小符号,例如12个字符,因此完整的表适合较少的数据库块。子字符串上的索引也可以工作,但需要仔细查询。
子字符串越长,查询运行得越快。为小子串创建一个单独的表,并将值存储在十大或您想要显示的任何选项中。大约有20000个1,2,3个字符串的组合。
如果你想要%abc%查询,你可以使用相同的想法,但现在切换到lucene是有道理的。
答案 2 :(得分:0)
你显然对150000+的结果不感兴趣,所以你应该限制它们:
select title,score
from nodes
where title ilike 's%'
order by score desc
limit 10;
您还可以考虑创建功能索引,并使用“&gt; =”和“&lt;”:
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%
案例。