Postgresql Растровое сканирование кучи медленное - PullRequest
2 голосов
/ 29 апреля 2019

Моя таблица выглядит следующим образом:

create table invoices
(
    id            serial not null,
    data          jsonb,
    modified      date,
    search_string text   not null
);

Мне нужно выполнить поиск в таблице с помощью ILIKE на search_string.
В одном запросе может быть много разных поисковых запросов.

Мой запрос выглядит так:

SELECT *
FROM invoices
WHERE (
    search_string ILIKE '%1%'
    OR search_string ILIKE '%2%'
    OR search_string ILIKE '%3%'
)

Объяснение поиска без индекса

Seq Scan on invoices  (cost=0.00..147139.51 rows=1004406 width=1006) (actual time=0.038..2341.489 rows=1004228 loops=1)
   Filter: ((search_string ~~* '%1%'::text) OR (search_string ~~* '%2%'::text) OR (search_string ~~* '%3%'::text))
   Rows Removed by Filter: 1943
 Planning Time: 4.682 ms
 Execution Time: 2427.400 ms

Я пытался ускорить его, создав индекс GIN:

CREATE EXTENSION pg_trgm;
CREATE INDEX invoices_search_string_trigram_index ON invoices USING gin (search_string gin_trgm_ops); 

Объясните, что поиск по индексу

 Bitmap Heap Scan on invoices_invoice  (cost=414767.41..561902.40 rows=1004149 width=1006) (actual time=14878.331..17862.840 rows=1004228 loops=1)
  Recheck Cond: ((search_string ~~* '%1%'::text) OR (search_string ~~* '%2%'::text) OR (search_string ~~* '%3%'::text))
  Rows Removed by Index Recheck: 1943
  Heap Blocks: exact=63341 lossy=66186
  ->  BitmapOr  (cost=414767.41..414767.41 rows=1006171 width=0) (actual time=14842.199..14842.199 rows=0 loops=1)
        ->  Bitmap Index Scan on trgm_idx_search_string  (cost=0.00..137979.36 rows=874048 width=0) (actual time=4520.466..4520.466 rows=546232 loops=1)
              Index Cond: (search_string ~~* '%1%'::text)
        ->  Bitmap Index Scan on trgm_idx_search_string  (cost=0.00..138208.03 rows=904538 width=0) (actual time=4357.453..4357.453 rows=546232 loops=1)
              Index Cond: (search_string ~~* '%2%'::text)
        ->  Bitmap Index Scan on trgm_idx_search_string  (cost=0.00..137826.91 rows=853721 width=0) (actual time=5964.276..5964.276 rows=546232 loops=1)
              Index Cond: (search_string ~~* '%3%'::text)
Planning Time: 1.198 ms
Execution Time: 17971.102 ms

Почему мой поиск по индексу медленнее, чем поиск по seq?
Есть ли способ ускорить поиск такого типа?

Ответы [ 2 ]

1 голос
/ 29 апреля 2019

Ваша проблема, вероятно, 66186 блоков с потерями. Увеличивайте work_mem, пока не получите только точные блоки.

Учитывая, что у вас есть миллион строк результата, я бы сказал, что этот запрос никогда не будет очень быстрым, если вы не уменьшите число до строк результата.

0 голосов
/ 19 июня 2019

Как насчет SIMILAR TO '[123]' вместо 3-х ILIKE, соединенных ИЛИ?Это может быть в 3 раза быстрее.

Тем не менее, ILIKE и SIMILAR должны проверять каждую строку.

Когда вы добавляете INDEX, вы заставляете оптимизатор думать, что индекс поможет.Но, вероятно, большинство строк содержат 1/2/3, поэтому индекс становится лишним.

Триграммы, как следует из названия, работают лучше всего, когда у вас есть 3 последовательных символа для сопоставления.Но %1% проверяет только 1 символ.Следовательно, большая часть силы триграмм теряется.

...