Sql 使用通配符的慢速连接查询
我有一个Sql 使用通配符的慢速连接查询,sql,postgresql,join,Sql,Postgresql,Join,我有一个关键字表,其中包含数百万个条目。它通过多对多关系链接到元素表。我想获得与关键字匹配的所有元素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.
关键字
表,其中包含数百万个条目。它通过多对多关系链接到元素
表。我想获得与关键字匹配的所有元素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)
执行计划:
"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)"
背后到底发生了什么?我该怎么解决呢
更新
我不确定这是否有帮助,但这里还有一些测试:
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
我认为您需要一个*_pattern_ops索引(请参阅): 原因是:
WHERE keyword.value like 'LOREM'
对于LIKE
操作符来说是一个毫无意义的用例。没有通配符(或转义字符),这实际上与:
WHERE keyword.value = 'LOREM'
WHERE keyword.value='LOREM'
。。它可以使用索引来表示相等-因此是一个普通B树索引
若您对匹配前导字符(左锚定搜索模式)感到满意,那个么使用操作符类text\u pattern\u ops
的B树索引将非常适合您。详细信息:对于任意模式匹配,请使用pg_trgm模块:
也许不是你想要的。它是基于字典和词干分析的,而不是像你的例子所建议的那样基于文本模式 此外,关键字(值、id)(列的顺序是相关的)上的多列索引可以启用仅索引扫描:
基本上,第二个查询正在进行顺序扫描(出于某些原因,我不理解)。这个顺序扫描花了这么长时间 禁用顺序扫描将强制查询使用索引。因此,如果我在查询之前执行这一行,它会变得非常快
set enable_seqscan to off;
您还可以显示此查询的执行计划吗?首先,如果您设计的数据库需要进行通配符搜索,那么您需要的是全文搜索,而不是通配符。通配符通常会妨碍索引的使用,而且性能非常差。@HLGEM嗯,是的,我可能会使用全文搜索,但经过一些测试后,我得到了大致相同的结果,除了现在……表关键字(value,id)上有索引吗?我不知道postgree,但在SQL server中,最好在索引中包含id列。好吧,我同意第一部分的观点,这更能说明区别。我对左锚定搜索模式很满意,我已经有了文本模式索引。我已经更新了我的帖子来展示我是如何创建索引的。我已经有了这个关于值的索引。我相信如果我没有这样做,像
select*from这样的请求,比如'LOREM%'这样的值代码>将不使用索引。不管怎样。
WHERE keyword.value like 'LOREM'
WHERE keyword.value = 'LOREM'
set enable_seqscan to off;