web-dev-qa-db-fra.com

Comment créer un index pour accélérer une requête LIKE agrégée sur une expression?

Je pose peut-être la mauvaise question dans le titre. Voici les faits:

Mes gens du service client se sont plaints de la lenteur des temps de réponse lors de la recherche de clients sur l'interface d'administration de notre site basé à Django.

Nous utilisons Postgres 8.4.6. J'ai commencé à enregistrer des requêtes lentes et j'ai découvert ce coupable:

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

Cette requête prend plus de 32 secondes pour s'exécuter. Voici le plan de requête fourni par 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)

Parce qu'il s'agit d'une requête générée par Django ORM à partir d'un Django QuerySet généré par l'application Django Admin), je ne 'ai aucun contrôle sur la requête elle-même. Un index semble être la solution logique. J'ai essayé de créer un index pour accélérer cela, mais cela n'a pas fait de différence:

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

Qu'est-ce que je fais mal? Comment puis-je accélérer cette requête?

22
David Eyk

Il n'y a pas de support d'index pour LIKE/ILIKE dans PostgreSQL 8.4 - sauf pour recherche ancrée à gauche termes .

Depuis PostgreSQL 9.1 le module supplémentaire pg_trgm fournit des classes d'opérateurs pour les index de trigrammes GIN et Gist prenant en charge LIKE/ILIKE ou des expressions régulières (opérateurs ~ et amis). Installez une fois par base de données:

CREATE EXTENSION pg_trgm;

Exemple d'index GIN:

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

En relation:

24
Erwin Brandstetter

Cet index ne va pas aider à cause du '%' au début de votre correspondance - un index BTREE ne peut correspondre qu'aux préfixes et le caractère générique au début de votre requête signifie qu'il n'y a pas de préfixe fixe à rechercher.

C'est pourquoi il effectue une analyse de table et fait correspondre chaque enregistrement tour à tour avec la chaîne de requête.

Vous devez probablement envisager d'utiliser un index de texte intégral et les opérateurs de correspondance de texte plutôt que de faire la recherche de sous-chaîne avec LIKE que vous êtes en ce moment. Vous pouvez trouver plus d'informations sur la recherche en texte intégral dans la documentation:

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

En fait, je remarque sur cette page que LIKE n'utilise apparemment jamais d'index, ce qui me semble étrange car il devrait être capable de résoudre les préfixes non génériques à l'aide d'un index BTREE. Quelques tests rapides suggèrent cependant que la documentation est probablement correcte, auquel cas aucune quantité d'indexation ne vous aidera pendant que vous utilisez LIKE pour résoudre la requête.

9
TomH