Индекс триграммы ORDER BY оптимизация

Я пытаюсь реализовать функцию поиска, и после некоторого исследования (см. Это интересное прочтение Йорика Петерсе в GitLab) я решил, что выберу триграмный подход, используя pg_trgm расширение.

Я хотел бы вернуть 10 самых важных строк.

Вот пара запросов, которые я протестировал (следуя документации) к таблице с 110868 строками:

SELECT name, similarity(name, 'search query') AS sml
FROM table
ORDER BY sml DESC, name;
Time: 701.814 ms

SELECT name, similarity(name, 'search query') AS sml
FROM table
WHERE name % 'search query'
ORDER BY sml DESC, name;
Time: 376.692 ms

SELECT name, similarity(name, 'search query') AS sml
FROM table
WHERE name % 'search query'
ORDER BY sml DESC, name LIMIT 10;
Time: 378.921 ms

С индексом GiST:

CREATE INDEX trigram_index ON table USING GIST (name gist_trgm_ops);
SELECT name, similarity(name, 'search query') AS sml
FROM table
WHERE name % 'search query'
ORDER BY sml DESC, name LIMIT 10;
Time: 36.877 ms

С индексом GIN:

CREATE INDEX trigram_index ON table USING GIN (name gin_trgm_ops);
SELECT name, similarity(name, 'search query') AS sml
FROM table WHERE name % 'search query'
ORDER BY sml DESC, name LIMIT 10;
Time: 18.992 ms

С ОБЪЯСНИТЬ АНАЛИЗ:

 Limit  (cost=632.37..632.39 rows=10 width=25) (actual time=22.202..22.204 rows=10 loops=1)
   ->  Sort  (cost=632.37..632.64 rows=111 width=25) (actual time=22.201..22.201 rows=10 loops=1)
         Sort Key: (similarity((name)::text, 'search query'::text)) DESC, name
         Sort Method: top-N heapsort  Memory: 26kB
         ->  Bitmap Heap Scan on table  (cost=208.86..629.97 rows=111 width=25) (actual time=6.900..22.157 rows=134 loops=1)
               Recheck Cond: ((name)::text % 'search query'::text)
               Rows Removed by Index Recheck: 2274
               Heap Blocks: exact=2257
               ->  Bitmap Index Scan on trigram_index  (cost=0.00..208.83 rows=111 width=0) (actual time=6.532..6.532 rows=2408 loops=1)
                     Index Cond: ((name)::text % 'World of Warcraft'::text)
 Planning time: 0.073 ms
 Execution time: 18.521 ms

Использование индекса GIN значительно повышает производительность. Ограничение результата до 10 строк, похоже, не оказывает никакого влияния.

Есть ли еще место для улучшения, которое я не рассматривал? Я особенно заинтересован в предложениях, которые могли бы использовать тот факт, что мне нужно только небольшое подмножество всей таблицы.

1 ответ

Решение

Как говорится в документации, индекс GIN не поможет оптимизировать ORDER BY пункт:

Вариант вышеупомянутого запроса

SELECT t, t <-> 'word' AS dist
FROM test_trgm
ORDER BY dist LIMIT 10;

Это может быть реализовано довольно эффективно с помощью индексов GiST, но не с помощью индексов GIN. Обычно он побьет первую формулировку, когда требуется лишь небольшое количество ближайших матчей.

С другой стороны, индексы GIN часто работают лучше, чем индексы GiST для больших таблиц.

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

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

Другие вопросы по тегам