Jag förväntar mig mycket snabbare resultat med detta tillvägagångssätt:
1.
Skapa ett GiST-index med en kolumn som innehåller sammanlänkade värden:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);
Detta förutsätter att alla tre kolumnerna är definierade NOT NULL
(du angav inte). Annars måste du göra mer.
Varför inte förenkla med concat_ws()
?
- Kombinera två kolumner och lägg till en ny kolumn
- Snabbare fråga med mönstermatchning i flera textfält
- Kombinera två kolumner och lägg till en ny kolumn
2.
Använd en riktig näraste-neighbor fråga som matchar ovanstående 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;
Uttryck i WHERE
och ORDER BY
måste matcha indexuttryck!
I synnerhet ORDER BY rank
(som du hade det) kommer alltid att fungera dåligt för en liten LIMIT
plocka från en mycket större pool av kvalificerande rader, eftersom den inte kan använda ett index direkt:Det sofistikerade uttrycket bakom rank
måste beräknas för varje kvalificeringsraden måste alla sorteras innan det lilla urvalet av bästa matcher kan returneras. Det här är mycket, mycket dyrare än en äkta fråga om närmaste granne som kan välja de bästa resultaten från indexet direkt utan att ens titta på resten.
row_number()
med tomt fönster återspeglar definitionen bara ordningen som produceras av ORDER BY
av samma SELECT
.
Relaterade svar:
När det gäller din artikel 3.
, Jag lade till ett svar på frågan du hänvisade till, som borde förklara det: