Oczekuję dużo szybsze wyniki dzięki temu podejściu:
1.
Utwórz indeks GiST z 1 kolumną zawierającą połączone wartości:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);
Zakłada się, że wszystkie 3 kolumny mają być zdefiniowane NOT NULL
(nie określiłeś). W przeciwnym razie musisz zrobić więcej.
Dlaczego nie uprościć za pomocą concat_ws()
?
- Połącz dwie kolumny i dodaj do jednej nowej
- Szybsze zapytania z dopasowywaniem wzorców do wielu pól tekstowych
- Połącz dwie kolumny i dodaj do jednej nowej
2.
Użyj prawidłowego najbliższy-sąsiad zapytanie, pasujące do powyższego indeksu:
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;
Wyrażenia w WHERE
i ORDER BY
musi pasować do wyrażenia indeksu!
W szczególności ORDER BY rank
(tak jak miałeś) zawsze będzie działać słabo dla małego LIMIT
wybieranie ze znacznie większej puli kwalifikujących się wierszy, ponieważ nie może bezpośrednio używać indeksu:Wyrafinowane wyrażenie stojące za rank
należy obliczyć dla każdej kwalifikacyjny wiersz, a następnie wszystkie muszą zostać posortowane, zanim będzie można zwrócić mały wybór najlepszych meczów. To jest znacznie, dużo droższe niż prawdziwe zapytanie najbliższego sąsiedztwa, które może wybrać najlepsze wyniki bezpośrednio z indeksu, nawet nie patrząc na resztę.
row_number()
z pustą definicją okna odzwierciedla tylko kolejność utworzoną przez ORDER BY
tego samego SELECT
.
Powiązane odpowiedzi:
Jeśli chodzi o Twój przedmiot 3.
, dodałem odpowiedź na zadane pytanie, która powinna to wyjaśnić: