我有一个表,其中包含从文本文档中提取的数据。数据存储在名为"CONTENT"
GIN 的列中,为此我创建了该索引:
CREATE INDEX "File_contentIndex"
ON "File"
USING gin
(setweight(to_tsvector('english'::regconfig
, COALESCE("CONTENT", ''::character varying)::text), 'C'::"char"));
我使用以下查询在表上执行全文搜索:
SELECT "ITEMID",
ts_rank(setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C') ,
plainto_tsquery('english', 'searchTerm')) AS "RANK"
FROM "File"
WHERE setweight(to_tsvector('english', coalesce("CONTENT",'')), 'C')
@@ plainto_tsquery('english', 'searchTerm')
ORDER BY "RANK" DESC
LIMIT 5;
“文件”表包含25万行,每个"CONTENT"
条目均包含一个随机词和一个文本字符串,所有行均相同。
现在,当我搜索一个随机单词(整个表中有1个匹配项)时,查询运行非常快(<100毫秒)。但是,当我搜索所有行中都存在的单词时,查询运行非常慢(10分钟或更长时间)。
EXPLAIN ANALYZE
显示对于1命中搜索,先执行位图索引扫描,再执行位图堆扫描。对于慢速搜索,将执行Seq扫描,这花费了很长时间。
当然,在所有行中都有相同的数据是不现实的。但是,由于我无法控制用户上载的文本文档,也无法控制用户执行的搜索,因此可能会出现类似的情况(搜索数据库中出现率很高的术语)。在这种情况下,如何提高搜索查询的性能?
运行PostgreSQL 9.3.4
查询计划EXPLAIN ANALYZE
:
快速搜索(在数据库中有1个匹配项)
"Limit (cost=2802.89..2802.90 rows=5 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" -> Sort (cost=2802.89..2806.15 rows=1305 width=26) (actual time=0.037..0.037 rows=1 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''wfecg'''::tsquery))"
" Sort Method: quicksort Memory: 25kB"
" -> Bitmap Heap Scan on "File" (cost=38.12..2781.21 rows=1305 width=26) (actual time=0.030..0.031 rows=1 loops=1)"
" Recheck Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
" -> Bitmap Index Scan on "File_contentIndex" (cost=0.00..37.79 rows=1305 width=0) (actual time=0.012..0.012 rows=1 loops=1)"
" Index Cond: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''wfecg'''::tsquery)"
"Total runtime: 0.069 ms"
搜索速度慢(数据库中有25万次匹配)
"Limit (cost=14876.82..14876.84 rows=5 width=26) (actual time=519667.404..519667.405 rows=5 loops=1)"
" -> Sort (cost=14876.82..15529.37 rows=261017 width=26) (actual time=519667.402..519667.402 rows=5 loops=1)"
" Sort Key: (ts_rank(setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char"), '''cyberspace'''::tsquery))"
" Sort Method: top-N heapsort Memory: 25kB"
" -> Seq Scan on "File" (cost=0.00..10541.43 rows=261017 width=26) (actual time=2.097..519465.953 rows=261011 loops=1)"
" Filter: (setweight(to_tsvector('english'::regconfig, (COALESCE("CONTENT", ''::character varying))::text), 'C'::"char") @@ '''cyberspace'''::tsquery)"
" Rows Removed by Filter: 6"
"Total runtime: 519667.429 ms"
explain (analyze, buffers)
,最好将track_io_timing设置为ON
?除非您将其存储在软盘的RAID中,否则没有必要花费520秒来对表进行顺序扫描。那里肯定是病态的。另外,您对的设置random_page_cost
以及其他费用参数?
ORDER BY "RANK" DESC
。我将pg_trgm
使用GiST索引和相似性/距离运算符作为替代进行调查。考虑:dba.stackexchange.com/questions/56224/…。甚至可能产生“更好”的结果(速度更快)。