PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Ottimizzazione di una query di somiglianza postgres (pg_trgm + gin index)

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() ?

2.

Usa un 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: