it-swarm.com.de

Wie erstelle ich einen Index, um eine aggregierte LIKE-Abfrage für einen Ausdruck zu beschleunigen?

Möglicherweise stelle ich im Titel die falsche Frage. Hier sind die Fakten:

Meine Kundendienstmitarbeiter haben sich über langsame Reaktionszeiten bei der Suche nach Kunden auf der Verwaltungsoberfläche unserer Django-basierten Website beschwert.

Wir verwenden Postgres 8.4.6. Ich begann langsame Abfragen zu protokollieren und entdeckte diesen Schuldigen:

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

Die Ausführung dieser Abfrage dauert mehr als 32 Sekunden. Hier ist der von EXPLAIN bereitgestellte Abfrageplan:

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)

Da dies eine Abfrage ist, die von der Django ORM aus einem Django QuerySet generiert wird, die von der Django Admin-Anwendung generiert wurde, habe ich keine Ich habe versucht, einen Index zu erstellen, um dies zu beschleunigen, aber es hat keinen Unterschied gemacht:

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

Was mache ich falsch? Wie kann ich diese Abfrage beschleunigen?

22
David Eyk

Es gibt keine Indexunterstützung für LIKE/ILIKE in PostgreSQL 8.4 - außer links verankerte Suche Begriffe .

Da PostgreSQL 9.1 das zusätzliche Modul pg_trgm Operatorklassen für GIN- und Gist-Trigrammindizes bereitstellt, die LIKE/ILIKE oder reguläre Ausdrücke (Operatoren ~ und Freunde). Einmal pro Datenbank installieren:

CREATE EXTENSION pg_trgm;

Beispiel GIN Index:

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

Verbunden:

24

Dieser Index hilft aufgrund des '%' zu Beginn Ihrer Übereinstimmung nicht weiter. Ein BTREE-Index kann nur mit Präfixen übereinstimmen, und der Platzhalter zu Beginn Ihrer Abfrage bedeutet, dass kein festes Präfix zu suchen ist.

Aus diesem Grund wird ein Tabellenscan durchgeführt und jeder Datensatz der Reihe nach mit der Abfragezeichenfolge abgeglichen.

Sie müssen wahrscheinlich einen Volltextindex und die Textabgleichsoperatoren verwenden, anstatt die Teilstringsuche mit LIKE durchzuführen, wie Sie es gerade sind. Weitere Informationen zur Volltextsuche finden Sie in der Dokumentation:

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

Tatsächlich stelle ich auf dieser Seite fest, dass LIKE anscheinend niemals Indizes verwendet, was mir seltsam erscheint, da es in der Lage sein sollte, Nicht-Wildcard-Präfixe mithilfe eines BTREE-Index aufzulösen. Ein paar schnelle Tests deuten darauf hin, dass die Dokumentation wahrscheinlich korrekt ist. In diesem Fall hilft keine Indizierung, während Sie LIKE zum Auflösen der Abfrage verwenden.

9
TomH