PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Optimieren einer Postgres-Ähnlichkeitsabfrage (pg_trgm + Gin-Index)

Ich erwarte viel schnellere Ergebnisse mit diesem Ansatz:

1.

Erstellen Sie einen GiST-Index mit 1 Spalte, die verkettete Werte enthält:

CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);

Dies setzt voraus, dass alle 3 Spalten definiert sind NOT NULL (Sie haben nicht angegeben). Andernfalls müssen Sie mehr tun.
Warum nicht mit concat_ws() vereinfachen ?

2.

Verwenden Sie einen geeigneten Abfrage, passend zum obigen Index:

SELECT username, email, first_name, last_name
     , similarity(username  , $1) AS s_username
     , similarity(first_name, $1) AS s_first_name
     , similarity(last_name , $1) AS s_last_name
     , row_number() OVER () AS rank  -- greatest similarity first
FROM   auth_user
WHERE     (username || ' ' || first_name || ' ' || last_name) %   $1  -- !!
ORDER  BY (username || ' ' || first_name || ' ' || last_name) <-> $1  -- !!
LIMIT  $2;

Ausdrücke in WHERE und ORDER BY muss Indexausdruck entsprechen!

Insbesondere ORDER BY rank (wie Sie es hatten) wird für ein kleines LIMIT immer schlecht funktionieren Auswahl aus einem viel größeren Pool qualifizierter Zeilen, da ein Index nicht direkt verwendet werden kann:Der ausgeklügelte Ausdruck hinter rank muss für jeden berechnet werden Qualifikationsreihe, dann müssen alle sortiert werden, bevor die kleine Auswahl der besten Übereinstimmungen zurückgegeben werden kann. Das ist viel, viel teurer als eine echte Nächster-Nachbar-Abfrage, die direkt die besten Ergebnisse aus dem Index auswählen kann, ohne sich den Rest auch nur anzusehen.

row_number() mit leerer Fensterdefinition spiegelt nur die Reihenfolge wider, die durch ORDER BY erzeugt wird desselben SELECT .

Verwandte Antworten:

Wie für Ihren Artikel 3. , ich habe eine Antwort auf die Frage hinzugefügt, auf die Sie verwiesen haben, die es erklären sollte: