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


20

Ich stelle möglicherweise die falsche Frage im Titel. Hier sind die Fakten:

Mein Kundenservice hat sich über langsame Antwortzeiten beschwert, als er auf der Administrationsoberfläche unserer Django-basierten Site nach Kunden gesucht hat.

Wir verwenden Postgres 8.4.6. Ich begann langsame Abfragen zu protokollieren und entdeckte diesen Täter:

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

Die Ausführung dieser Abfrage dauert mindestens 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 vom Django ORM aus einem Django QuerySet generiert wurde, das von der Django Admin-Anwendung generiert wurde, kann ich die Abfrage selbst nicht steuern. Ein Index scheint die logische Lösung zu sein. 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?

Antworten:


21

Es gibt keine Indexunterstützung für LIKE/ ILIKEin PostgreSQL 8.4 - mit Ausnahme von links verankerten Suchbegriffen .

Seit PostgreSQL 9.1pg_trgm bietet das Zusatzmodul Operator-Klassen für GIN- und GiST-Trigrammindizes, die LIKE/ ILIKEoder reguläre Ausdrücke (Operatoren ~und Freunde) unterstützen. 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:


2
Das ist eigentlich die richtige Antwort.
vonPetrushev

9

Dieser Index ist nicht hilfreich, da zu Beginn Ihres Abgleichs ein '%' angezeigt wird. Ein BTREE-Index kann nur Präfixe abgleichen, und der Platzhalter am Anfang Ihrer Abfrage bedeutet, dass kein festes Präfix gesucht werden muss.

Aus diesem Grund wird ein Tabellenscan durchgeführt, bei dem alle Datensätze der Reihe nach mit der Abfragezeichenfolge abgeglichen werden.

Wahrscheinlich müssen Sie einen Volltextindex und die Textvergleichsoperatoren verwenden, anstatt die Teilstringsuche mit LIKE durchzuführen, wie Sie es gerade tun. 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-Platzhalter-Präfixe mithilfe eines BTREE-Index aufzulösen. Ein paar schnelle Tests deuten jedoch darauf hin, dass die Dokumentation wahrscheinlich korrekt ist. In diesem Fall hilft kein Indizierungsaufwand, während Sie LIKE zum Auflösen der Abfrage verwenden.


Davor hatte ich Angst. Gibt es eine andere Art von Index, der helfen wird? Wie gesagt, ich bin etwas eingeschränkt in meiner Fähigkeit, die Abfrage selbst zu beeinflussen.
David Eyk

Das führende %Merkmal ist auch ein notwendiges Merkmal: Die Kundendienstmitarbeiter benötigen es zum Auffinden von Kundenkonten, insbesondere wenn die E-Mail-Adresse einen Tippfehler enthält.
David Eyk

Nun, nach ein wenig Recherche über LIKE und Volltextindizierung, und ich beginne, Ihren Standpunkt zu verstehen.
David Eyk

Im Moment habe ich einen Weg gefunden, um den führenden Platzhalter zu unterdrücken. Es stellt sich heraus , Sie können einen Index mit LIKE verwenden, wenn Sie den Index mit einem geeigneten erstellen Operatorklasse . Die Dokumentation
David Eyk

Überprüfen Sie auch Ihre Datenbank auf Aufblähung. Wenn Sie in dieser Tabelle viel Aufblähung haben, wird es lange dauern, bis der Scanvorgang abgeschlossen ist. Wenn Sie eine gewisse Ausfallzeit haben, gruppieren Sie sie einfach auf dem Primärschlüssel und prüfen Sie, ob sie schneller wird. Wenn Sie nach Aufblähungen suchen möchten, können Sie eine Analyse ausführen und die Abfrage hier ausführen : wiki.postgresql.org/wiki/Show_database_bloat . Genauere Werte finden Sie unten auf dieser Seite.
Scott Marlowe
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.