我正在完善Postgres文本搜索查询,以确保在可能的情况下使用所有可用的索引。我在文本列上有一个text_pattern_obs btree索引,该索引已显示为可以使用简单的查询来工作,例如:
set enable_seqscan = off; -- ensure that indexes are used even on small tables for this demo
select * from search_table where text_column like 'example'
^^这为我提供了使用适当索引的超快速查询。
但是当我想用单个字符串值代替我的'example'文本时,该字符串值是前一个函数或select的结果,它将恢复为完整的顺序表扫描。
with user_input as (select 'example%' as query_string)
select * from search_table, user_input where text_column like query_string
^^这很慢
我尝试过类型转换query_string :: text等,但是没有任何运气。而且我不能只是将字符串直接插入sql中,因为在执行其他查询之前它是未知的。
我正在使用postgres v11,因此应该具有所有最新的查询计划的灵巧性。
尝试使用准备好的语句而不是联接:
使用:
create table t(x int, y text);
create index fts on t(y text_pattern_ops);
insert into t values(1, 'example');
insert into t values(2, 'examples');
insert into t values(3, 'aaa');
insert into t values(4, 'zzz zzz');
analyze t;
set enable_seqscan = off;
我有:
select * from t;
x | y
---+----------
1 | example
2 | examples
3 | aaa
4 | zzz zzz
(4 rows)
explain analyze select * from t where y like 'example';
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Index Scan using fts on t (cost=0.13..8.15 rows=1 width=11) (actual time=0.012..0.013 rows=1 loops=1)
Index Cond: (y = 'example'::text)
Filter: (y ~~ 'example'::text)
Planning Time: 0.111 ms
Execution Time: 0.030 ms
(5 rows)
explain analyze select * from t where y like 'example%';
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Index Scan using fts on t (cost=0.13..8.15 rows=1 width=11) (actual time=0.006..0.007 rows=2 loops=1)
Index Cond: ((y ~>=~ 'example'::text) AND (y ~<~ 'examplf'::text))
Filter: (y ~~ 'example%'::text)
Planning Time: 0.140 ms
Execution Time: 0.014 ms
(5 rows)
explain analyze with user_input as (select 'example%' as query_string)
select * from t, user_input where y like query_string;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
----
Nested Loop (cost=10000000000.01..10000000001.15 rows=1 width=43) (actual time=0.008..0.011 rows=2 loops=1)
Join Filter: (t.y ~~ user_input.query_string)
Rows Removed by Join Filter: 2
CTE user_input
-> Result (cost=0.00..0.01 rows=1 width=32) (actual time=0.001..0.001 rows=1 loops=1)
-> Seq Scan on t (cost=10000000000.00..10000000001.04 rows=4 width=11) (actual time=0.003..0.003 rows=4 loops
=1)
-> CTE Scan on user_input (cost=0.00..0.02 rows=1 width=32) (actual time=0.001..0.001 rows=1 loops=4)
Planning Time: 0.049 ms
Execution Time: 0.031 ms
(9 rows)
prepare s1(text) as select * from t where y like $1;
PREPARE
explain analyze execute s1('example%');
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Index Scan using fts on t (cost=0.13..8.15 rows=1 width=11) (actual time=0.012..0.014 rows=2 loops=1)
Index Cond: ((y ~>=~ 'example'::text) AND (y ~<~ 'examplf'::text))
Filter: (y ~~ 'example%'::text)
Planning Time: 0.089 ms
Execution Time: 0.023 ms
(5 rows)