我有一个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
型
3条答案
按热度按时间vdzxcuhz1#
原因是这样的:
字符串
对于
LIKE
运算符来说是一个毫无意义的用例。如果没有通配符(或转义字符),这实际上与以下内容相同:型
..,它可以使用索引进行相等-因此是普通B树索引。
如果您对匹配前导字符(左锚定搜索模式)感到满意,那么带有运算符类
text_pattern_ops
或COLLATE "C"
的B树索引将非常有用。请参阅:对于任意模式匹配,使用pg_trgm模块:
Full text search可能是也可能不是你想要的。它基于字典和词干分析,而不是像您的示例所建议的那样基于文本模式。
此外,
keyword (value,id)
上的多列索引(列的顺序是相关的)可以启用仅索引扫描:n53p2ov02#
我相信你需要一个 *_pattern_ops索引(参见http://www.postgresql.org/docs/9.3/static/indexes-opclass.html):
字符串
qfe3c7zg3#
基本上发生的是第二个查询正在进行顺序扫描(出于一些我不理解的原因)。就是这个顺序扫描花了这么长时间
禁用顺序扫描将强制查询使用索引。所以如果我在查询之前执行这行代码,它会变得非常快。
字符串