Могу ли я использовать индекс postgres text_pattern_ops с переменной строкой? - PullRequest
0 голосов
/ 28 мая 2020

Я уточняю текстовый поисковый запрос Postgres, чтобы убедиться, что все доступные индексы используются там, где это возможно. У меня есть индекс btree text_pattern_obs в текстовом столбце, и было показано, что этот индекс работает с использованием простого запроса, например:

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'

^^, это дает мне очень быстрый запрос с использованием правильного индекса.

Но когда я хочу заменить мой «примерный» текст одним строковым значением, которое является результатом предыдущей функции или выбора, он возвращается к полному последовательному сканированию таблицы.

with user_input as (select 'example%' as query_string)
select * from search_table, user_input where text_column like query_string

^^ это медленно

Я пробовал использовать приведение типов query_string :: text et c, но безуспешно. И я не могу просто вставить строку в sql напрямую, потому что она неизвестна до тех пор, пока не будут выполнены другие запросы.

Я использую postgres v11, поэтому должны быть доступны все новейшие возможности плана запроса.

1 Ответ

0 голосов
/ 28 мая 2020

Попробуйте использовать подготовленный оператор вместо соединения:

С:

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)
...