postgresql 使用通配符的慢速连接查询

ws51t4hk  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(3)|浏览(134)

我有一个keyword表,其中包含数百万个条目。它通过多对多关系链接到element表。我想得到所有匹配关键字的元素ID。我尝试了这个查询,没有问题,它在几毫秒内返回行。

SELECT element_id FROM element_keyword 
JOIN keyword ON keyword.id = element_keyword.keyword_id
WHERE keyword.value like 'LOREM';

字符串
执行计划

"Nested Loop  (cost=278.50..53665.56 rows=65 width=4)"
"  ->  Index Scan using keyword_value_index on keyword  (cost=0.43..8.45 rows=1 width=4)"
"        Index Cond: ((value)::text = 'LOREM'::text)"
"        Filter: ((value)::text ~~ 'LOREM'::text)"
"  ->  Bitmap Heap Scan on element_keyword  (cost=278.07..53510.66 rows=14645 width=8)"
"        Recheck Cond: (keyword_id = keyword.id)"
"        ->  Bitmap Index Scan on element_keyword_keyword_index  (cost=0.00..274.41 rows=14645 width=0)"
"              Index Cond: (keyword_id = keyword.id)"


然而,当我在搜索字符串的末尾放一个通配符时,请求变得非常慢。(~60000ms)

SELECT element_id FROM element_keyword 
JOIN keyword ON keyword.id = element_keyword.keyword_id
WHERE keyword.value like 'LOREM%';


执行计划:

"Hash Join  (cost=12.20..3733738.08 rows=19502 width=4)"
"  Hash Cond: (element_keyword.keyword_id = keyword.id)"
"  ->  Seq Scan on element_keyword  (cost=0.00..3002628.08 rows=194907408 width=8)"
"  ->  Hash  (cost=8.45..8.45 rows=300 width=4)"
"        ->  Index Scan using keyword_value_index on keyword  (cost=0.43..8.45 rows=300 width=4)"
"              Index Cond: (((value)::text ~>=~ 'LOREM'::text) AND ((value)::text ~<~ 'LOREN'::text))"
"              Filter: ((value)::text ~~ 'LOREM%'::text)"


即使通配符没有给予更多的结果,查询也很慢。
我在keyword(value)和element_keyword(keyword_id)上创建了一个索引

CREATE INDEX "keyword_value_index" ON "keyword" (value text_pattern_ops);
CREATE INDEX "element_keyword_keyword_index" ON "element_keyword" (keyword_id);


后面到底发生了什么?我该怎么解决呢?

更新

我不确定这是否有帮助,但这里有一些测试:

select id from keyword where value like 'LOREM%'; 
-> 6 ids retrieved in 17ms 

select * from element_keyword where keyword_id in (1961746,1961710,2724258,2121442,1633163,1026116); 
-> 40 rows retrieved in 17ms

select * from element_keyword where keyword_id in (select id from keyword where value like 'LOREM%');
-> 40 rows in 63221 ms

vdzxcuhz

vdzxcuhz1#

原因是这样的:

WHERE keyword.value like 'LOREM'

字符串
对于LIKE运算符来说是一个毫无意义的用例。如果没有通配符(或转义字符),这实际上与以下内容相同:

WHERE keyword.value = 'LOREM'


..,它可以使用索引进行相等-因此是普通B树索引
如果您对匹配前导字符(左锚定搜索模式)感到满意,那么带有运算符类text_pattern_opsCOLLATE "C"的B树索引将非常有用。请参阅:

  • 在Postgres或CouchDB中进行全文搜索?

对于任意模式匹配,使用pg_trgm模块:

  • PostgreSQL LIKE查询性能变化

Full text search可能是也可能不是你想要的。它基于字典和词干分析,而不是像您的示例所建议的那样基于文本模式。

此外,keyword (value,id)上的多列索引(列的顺序是相关的)可以启用仅索引扫描:

n53p2ov0

n53p2ov02#

我相信你需要一个 *_pattern_ops索引(参见http://www.postgresql.org/docs/9.3/static/indexes-opclass.html):

create index pattern_idx on keyword(value text_pattern_ops)

字符串

qfe3c7zg

qfe3c7zg3#

基本上发生的是第二个查询正在进行顺序扫描(出于一些我不理解的原因)。就是这个顺序扫描花了这么长时间
禁用顺序扫描将强制查询使用索引。所以如果我在查询之前执行这行代码,它会变得非常快。

set enable_seqscan to off;

字符串

相关问题