Mi aspetto molto risultati più rapidi con questo approccio:
1.
Crea un indice GiST con 1 colonna contenente valori concatenati:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);
Ciò presuppone che tutte e 3 le colonne siano definite NOT NULL
(non hai specificato). Altrimenti devi fare di più.
Perché non semplificare con concat_ws()
?
- Combina due colonne e aggiungile in una nuova colonna
- Query più veloce con corrispondenza di modelli su più campi di testo
- Combina due colonne e aggiungile in una nuova colonna
2.
Usa un neighbor più vicino query, corrispondente sopra l'indice:
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;
Espressioni in WHERE
e ORDER BY
deve corrispondere all'espressione dell'indice!
In particolare ORDER BY rank
(come avevi tu) funzionerà sempre male per un piccolo LIMIT
selezionando da un pool molto più ampio di righe di qualificazione, perché non può utilizzare direttamente un indice:l'espressione sofisticata dietro rank
deve essere calcolato per ogni riga di qualificazione, quindi tutti devono essere ordinati prima che la piccola selezione delle migliori partite possa essere restituita. Questo è molto, molto più costoso rispetto a una vera query del vicino più vicino in grado di raccogliere i risultati migliori direttamente dall'indice senza nemmeno guardare il resto.
row_number()
con la definizione di finestra vuota riflette solo l'ordinamento prodotto da ORDER BY
dello stesso SELECT
.
Risposte correlate:
Per quanto riguarda il tuo articolo 3.
, ho aggiunto una risposta alla domanda che hai fatto riferimento, che dovrebbe spiegarlo: