Я пытался быть тщательными в этом вопросе, так что если вы нетерпеливы, просто прыгать до конца, чтобы увидеть, что фактический вопрос ...Postgresql КАК ЛЮБОЙ против LIKE
Я работаю над настройка некоторых функций поиска в одной из наших баз данных. С этой целью я добавляю некоторые подстановочные возможности API нашего приложения, которые обращаются к Postgresql.
Проблема, которую я обнаружил, заключается в том, что EXPLAIN ANALYZE
раз не имеет смысла для меня, и я пытаюсь выяснить, где я могу ошибиться; похоже, что 15 запросов лучше, чем только один оптимизированный запрос!
Таблица, Words
, имеет две соответствующие колонки по этому вопросу: id
и text
. Столбец text
имеет индекс, который был построен с опцией text_pattern_ops
. Вот что я вижу:
Во-первых, с помощью LIKE ANY
с положением в VALUES
, который some references, кажется, показывают, было бы идеально в моем случае (найти несколько слов):
events_prod=# explain analyze select distinct id from words where words.text LIKE ANY (values('test%'));
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=6716668.40..6727372.85 rows=1070445 width=4) (actual time=103088.381..103091.468 rows=256 loops=1)
Group Key: words.id
-> Nested Loop Semi Join (cost=0.00..6713992.29 rows=1070445 width=4) (actual time=0.670..103087.904 rows=256 loops=1)
Join Filter: ((words.text)::text ~~ "*VALUES*".column1)
Rows Removed by Join Filter: 214089311
-> Seq Scan on words (cost=0.00..3502655.91 rows=214089091 width=21) (actual time=0.017..25232.135 rows=214089567 loops=1)
-> Materialize (cost=0.00..0.02 rows=1 width=32) (actual time=0.000..0.000 rows=1 loops=214089567)
-> Values Scan on "*VALUES*" (cost=0.00..0.01 rows=1 width=32) (actual time=0.006..0.006 rows=1 loops=1)
Planning time: 0.226 ms
Execution time: 103106.296 ms
(10 rows)
Как вы можете видеть, время исполнения является ужасным.
Вторая попытка, используя LIKE ANY(ARRAY[...
выходы:
events_prod=# explain analyze select distinct id from words where words.text LIKE ANY(ARRAY['test%']);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=3770401.08..3770615.17 rows=21409 width=4) (actual time=37399.573..37399.704 rows=256 loops=1)
Group Key: id
-> Seq Scan on words (cost=0.00..3770347.56 rows=21409 width=4) (actual time=0.224..37399.054 rows=256 loops=1)
Filter: ((text)::text ~~ ANY ('{test%}'::text[]))
Rows Removed by Filter: 214093922
Planning time: 0.611 ms
Execution time: 37399.895 ms
(7 rows)
Как вы можете видеть, производительность значительно улучшилась, но все еще далеко от идеала ... 37 секунд. с одним словом в списке. Перемещение до трех слов, которое возвращает в общей сложности 256 строк, изменяет время выполнения на более чем 100 секунд.
Последняя попытка, делает LIKE для одного слова:
events_prod=# explain analyze select distinct id from words where words.text LIKE 'test%';
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=60.14..274.23 rows=21409 width=4) (actual time=1.437..1.576 rows=256 loops=1)
Group Key: id
-> Index Scan using words_special_idx on words (cost=0.57..6.62 rows=21409 width=4) (actual time=0.048..1.258 rows=256 loops=1)
Index Cond: (((text)::text ~>=~ 'test'::text) AND ((text)::text ~<~ 'tesu'::text))
Filter: ((text)::text ~~ 'test%'::text)
Planning time: 0.826 ms
Execution time: 1.858 ms
(7 rows)
Как и следовало ожидать, это самый быстрый, но 1.85ms заставляет меня задаться вопросом, есть ли что-то еще, что я пропускаю с VALUES
и ARRAY
подход.
Вопрос
Есть ли более эффективный способ сделать что-то подобное в Postgresql, что я пропустил в своих исследованиях?
select distinct id
from words
where words.text LIKE ANY(ARRAY['word1%', 'another%', 'third%']);
Вы проверили регулярное выражение или версию «похоже на»? Что-то вроде 'words.text ~ '^ (word1 | another | third)' или' words.text похоже на '(word1 | another | third)% '. –
Да. Первая версия, которую вы предлагаете, анализирует более чем на 202 секунды. Все мои исследования говорят, чтобы избежать «ПОДОБНОГО ТОКА» любой ценой, и это также подтверждается анализом результатов за 197 секунд, только перед регулярным выражением. –
Считаете ли вы использование [полного текстового индекса] (https://www.postgresql.org/docs/current/static/textsearch.html)? –