Як створити індекс для прискорення сукупного запиту LIKE на вираз?


20

Можливо, я задаю неправильне запитання в заголовку. Ось факти:

Мої фольклорні служби скаржаться на повільний час реакції під час пошуку клієнтів на інтерфейсі адміністрування нашого сайту на базі Джанго.

Ми використовуємо Postgres 8.4.6. Я почав реєструвати повільні запити і виявив цього вину:

SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')

Цей запит займає понад 32 секунди. Ось план запитів, наданий EXPLAIN:

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)

Оскільки це запит, згенерований ORM Django з Django QuerySet, згенерований програмою Django Admin, я не маю ніякого контролю над самим запитом. Індекс здається логічним рішенням. Я спробував створити індекс, щоб прискорити це, але це не змінило:

CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))

Що я роблю неправильно? Як я можу пришвидшити цей запит?

Відповіді:


21

Підтримка індексу для LIKE/ ILIKEу PostgreSQL 8.4 не існує - за винятком ліворізованих пошукових термінів .

Оскільки PostgreSQL 9.1, додатковий модуль pg_trgmзабезпечує операторські класи для індексів триграмів GIN та GiST, що підтримують LIKE/ ILIKEабо регулярні вирази (оператори ~та друзі). Встановіть один раз у базі даних:

CREATE EXTENSION pg_trgm;

Приклад індексу GIN:

CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);

Пов'язані:


2
Це насправді правильна відповідь.
фонПетрушев

9

Цей індекс не допоможе через "%" на початку вашої відповідності - індекс BTREE може відповідати лише префіксам, а підстановка на початку запиту означає, що фіксований префікс не потрібно шукати.

Ось чому він робить сканування таблиці та порівнює кожен запис по черзі з рядком запиту.

Вам, напевно, потрібно звернути увагу на використання повного текстового індексу та операторів відповідності тексту, а не робити пошук підрядків з LIKE, який ви зараз перебуваєте. Більше про повний текст можна знайти в документації:

http://www.postgresql.org/docs/8.4/static/textsearch-intro.html

Насправді я помічаю на цій сторінці, що LIKE, мабуть, ніколи не використовує індекси, що мені здається дивним, оскільки він повинен мати можливість вирішувати префікси, що не мають підказки, використовуючи індекс BTREE. Кілька швидких тестів свідчать про те, що документація, ймовірно, правильна, але в цьому випадку жодна кількість індексації не допоможе, коли ви використовуєте LIKE для вирішення запиту.


Ось чого я боявся. Чи є інший вид індексу, який допоможе? Як я вже сказав, я трохи обмежений у своїй здатності впливати на сам запит.
David Eyk

Крім того, головною %є необхідна особливість: представники служби обслуговування клієнтів потребують її для пошуку облікових записів клієнтів, особливо, коли в адресі електронної пошти є помилка друку.
Девід Ейк

Ну, після невеликих досліджень щодо LIKE та повнотекстової індексації, і я починаю бачити вашу думку.
Девід Ейк

Наразі я знайшов спосіб придушити провідну підстановку. Виявляється, ви можете використовувати індекс з LIKE, якщо створити індекс з відповідним класом операторів . Документи тут: postgresql.org/docs/8.4/static/indexes-opclass.html
Девід Ейк

Крім того, перевірте свій db на набряк. Якщо у вас в цій таблиці багато процвітання, її сканування буде тривати багато часу. Якщо у вас є час простою, просто клацніть його на первинному ключі і подивіться, чи стане він швидше. Якщо ви хочете перевірити наявність жирності, можете запустити аналіз, а потім запустіть запит тут: wiki.postgresql.org/wiki/Show_database_bloat . Більш точні значення див. У нижній частині цієї сторінки.
Скотт Марлоу
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.