我已经尝试过彻底解决这个问题了,所以如果你不耐烦,那就跳到最后看看实际问题是什么......
我正致力于调整我们某个数据库中某些搜索功能的实施方式。为此,我将一些通配符功能添加到我们的应用程序API中,该API与Postgresql接口。
我发现的问题是EXPLAIN ANALYZE
次对我没有意义,我试图找出可能出错的地方;它似乎不太可能15个查询优于一个优化查询!
表格Words
包含两个相关的问题列:id
和text
。 text
列上有一个使用text_pattern_ops
选项构建的索引。这就是我所看到的:
首先,使用带有LIKE ANY
子句的VALUES
some references似乎表明在我的情况下是理想的(找到多个单词):
events_prod=# explain analyze select distinct id from words where words.text LIKE ANY (values('test%'));
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=6716668.40..6727372.85 rows=1070445 width=4) (actual time=103088.381..103091.468 rows=256 loops=1)
Group Key: words.id
-> Nested Loop Semi Join (cost=0.00..6713992.29 rows=1070445 width=4) (actual time=0.670..103087.904 rows=256 loops=1)
Join Filter: ((words.text)::text ~~ "*VALUES*".column1)
Rows Removed by Join Filter: 214089311
-> Seq Scan on words (cost=0.00..3502655.91 rows=214089091 width=21) (actual time=0.017..25232.135 rows=214089567 loops=1)
-> Materialize (cost=0.00..0.02 rows=1 width=32) (actual time=0.000..0.000 rows=1 loops=214089567)
-> Values Scan on "*VALUES*" (cost=0.00..0.01 rows=1 width=32) (actual time=0.006..0.006 rows=1 loops=1)
Planning time: 0.226 ms
Execution time: 103106.296 ms
(10 rows)
正如您所看到的,执行时间非常可怕。
使用LIKE ANY(ARRAY[...
的第二次尝试产生:
events_prod=# explain analyze select distinct id from words where words.text LIKE ANY(ARRAY['test%']);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=3770401.08..3770615.17 rows=21409 width=4) (actual time=37399.573..37399.704 rows=256 loops=1)
Group Key: id
-> Seq Scan on words (cost=0.00..3770347.56 rows=21409 width=4) (actual time=0.224..37399.054 rows=256 loops=1)
Filter: ((text)::text ~~ ANY ('{test%}'::text[]))
Rows Removed by Filter: 214093922
Planning time: 0.611 ms
Execution time: 37399.895 ms
(7 rows)
正如您所看到的,性能得到了显着提升,但仍然远非理想...... 37秒。列表中有一个单词。将最多三个单词移动总共256行会将执行时间更改为超过100秒。
最后一次尝试,为一个单词做一个LIKE:
events_prod=# explain analyze select distinct id from words where words.text LIKE 'test%';
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=60.14..274.23 rows=21409 width=4) (actual time=1.437..1.576 rows=256 loops=1)
Group Key: id
-> Index Scan using words_special_idx on words (cost=0.57..6.62 rows=21409 width=4) (actual time=0.048..1.258 rows=256 loops=1)
Index Cond: (((text)::text ~>=~ 'test'::text) AND ((text)::text ~<~ 'tesu'::text))
Filter: ((text)::text ~~ 'test%'::text)
Planning time: 0.826 ms
Execution time: 1.858 ms
(7 rows)
正如预期的那样,这是最快的,但是1.85毫秒让我想知道VALUES
和ARRAY
方法是否还有其他的东西。
问题
在我的研究中我是否有一些更有效的方法可以在Postgresql中做这样的事情?
select distinct id
from words
where words.text LIKE ANY(ARRAY['word1%', 'another%', 'third%']);
答案 0 :(得分:2)
这有点推测。我认为关键是你的模式:
where words.text LIKE 'test%'
请注意,like
模式以常量字符串开头。这意味着Postgres可以对索引进行范围扫描,以查找以'test'
开头的单词。
当您再引入多个比较时,优化器会感到困惑,不再考虑多个范围扫描。相反,它决定它需要处理所有行。
这可能是这种重写为您提供所需性能的情况:
select id
from words
where words.text LIKE 'word1%'
union
select id
from words
where words.text LIKE 'another%'
union
select id
from words
where words.text LIKE 'third%';
注意:
distinct
。union