Как создать индекс, чтобы ускорить агрегат, как запрос на выражение?
-
16-10-2019 - |
Вопрос
Я могу задать неправильный вопрос в названии. Вот факты:
Мои люди по обслуживанию клиентов жаловались на медленное время отклика при поиске клиентов на интерфейсе администрирования нашего сайта на основе Django.
Мы используем Postgres 8.4.6. Я начал регистрировать медленные запросы и обнаружил этого виновника:
SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')
Этот запрос занимает более 32 секунд. Вот план запроса, предоставленный объяснением:
QUERY PLAN
Aggregate (cost=205171.71..205171.72 rows=1 width=0)
-> Seq Scan on auth_user (cost=0.00..205166.46 rows=2096 width=0)
Filter: (upper((email)::text) ~~ '%DEYK%'::text)
Поскольку это запрос, генерируемый Django Orm из запроса Django, сгенерированного приложением администратора Django, у меня нет никакого контроля над самим запросом. Индекс выглядит как логическое решение. Я попытался создать индекс, чтобы ускорить это, но это не изменило:
CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))
Что я делаю не так? Как я могу ускорить этот запрос?
Решение
Нет индексной поддержки LIKE
/ ILIKE
в Postgresql 8.4 - кроме оставлены на якоре поисковых терминов.
С Postgresql 9.1 Дополнительный модуль pg_trgm
Предоставляет классы операторов для индексов триграмм джина и GIST поддержки LIKE
/ ILIKE
или регулярные выражения (операторы ~
и друзья). Установите один раз на базу данных:
CREATE EXTENSION pg_trgm;
Пример индекса джина:
CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);
Связанный:
Другие советы
Этот индекс не поможет из -за «%» в начале вашего матча - индекс Btree может соответствовать только префиксам, а подстановка в начале вашего запроса означает, что нет фиксированного префикса.
Вот почему он делает сканирование таблицы и соответствует каждой записи по очереди на строку запроса.
Возможно, вам нужно посмотреть на использование полного текстового индекса и операторов сопоставления текста, а не выполнять поиск подстроения с такими же вы в данный момент. Вы можете найти больше на полном поиске текста в документации:
http://www.postgresql.org/docs/8.4/static/textsearch-intro.html
На самом деле я замечаю со этой страницы, которая, по-видимому, никогда не использует индексы, что мне кажется странным, поскольку он должен иметь возможность разрешать префиксы не-WildCard с использованием индекса Btree. Несколько быстрых тестов предполагают, что документация, вероятно, верна, однако, в этом случае ни одно из них не поможет, пока вы используете как для разрешения запроса.