Индекс Postgres `gin_trgm_ops` не используется - PullRequest
0 голосов
/ 07 июня 2019

Я пытаюсь ускорить сопоставление текста в Postgres, используя pg_trgm расширения:

CREATE TABLE test3 (id bigint, key text, value text);

insert into test3 values (1, 'first 1', 'second 3');
insert into test3 values (2, 'first 1', 'second 2');
insert into test3 values (2, 'first 2', 'second 3');
insert into test3 values (3, 'first 1', 'second 2');
insert into test3 values (3, 'first 1', 'second 3');
insert into test3 values (4, 'first 2', 'second 3');
insert into test3 values (4, 'first 2', 'second 3');
insert into test3 values (4, 'first 1', 'second 2');
insert into test3 values (4, 'first 1', 'second 2');

-- repeat the above 1,000,000x times, to have more rows for benchmarking
insert into test3(id, key, value) select id, key, value from test3 cross join generate_series(1, 1000000);

Теперь я запрашиваю эту таблицу с помощью ILIKE:

select count(*) from test3 where key = 'first 1' and value ilike '%nd 3%';
Time: 918.265 ms

Чтобы увидеть, ускорит ли это индексацию, я добавил pg_trgm в оба столбца key и value:

CREATE extension if not exists pg_trgm;
CREATE INDEX test3_key_trgm_idx ON test3 USING gin (key gin_trgm_ops);
CREATE INDEX test3_value_trgm_idx ON test3 USING gin (value gin_trgm_ops);

Но запрос все еще занимает то же время,и EXPLAIN ANALYZE показывает, что индексы вообще не используются:

explain analyze select count(*) from test3 where key = 'first 1' and value ilike '%nd 3%';
                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=126905.14..126905.15 rows=1 width=8) (actual time=1017.666..1017.667 rows=1 loops=1)
   ->  Gather  (cost=126904.93..126905.14 rows=2 width=8) (actual time=1017.505..1018.778 rows=3 loops=1)
         Workers Planned: 2
         Workers Launched: 2
         ->  Partial Aggregate  (cost=125904.93..125904.94 rows=1 width=8) (actual time=1010.862..1010.862 rows=1 loops=3)
               ->  Parallel Seq Scan on test3  (cost=0.00..122427.06 rows=1391148 width=0) (actual time=0.041..973.550 rows=666667 loops=3)
                     Filter: ((value ~~* '%nd 3%'::text) AND (key = 'first 1'::text))
                     Rows Removed by Filter: 2333336
 Planning Time: 0.266 ms
 Execution Time: 1018.814 ms

Time: 1049.413 ms (00:01.049)

Обратите внимание на последовательное сканирование.Что дает?

1 Ответ

3 голосов
/ 07 июня 2019

Не берите в голову, я нашел проблему.

Планировщик запросов был умнее, чем мой игрушечный тестовый набор;видя, что большинство строк соответствуют запросу, он пошел на последовательное сканирование.

Если я попытаюсь вместо этого использовать ilike '%nd 0%', ни одна строка не совпадет, и EXPLAIN ANALYZE сообщит Bitmap Index Scan on test3_value_trgm_idx правильно.

Итак,нормализация исходного JSONB таким образом работает.Но я также попытаюсь найти и сравнить другой способ, используя регулярные выражения над TEXT, чтобы избежать необходимости создавать и поддерживать другую таблицу.

...