PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Optimisation d'une requête de similarité postgres (pg_trgm + gin index)

J'attends beaucoup des résultats plus rapides avec cette approche :

1.

Créez un index GiST avec 1 colonne contenant des valeurs concaténées :

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

Cela suppose que les 3 colonnes sont définies NOT NULL (vous n'avez pas précisé). Sinon, vous devez en faire plus.
Pourquoi ne pas simplifier avec concat_ws() ?

2.

Utilisez un requête, correspondant au-dessus de l'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;

Expressions dans WHERE et ORDER BY doit correspondre à l'expression d'index !

En particulier ORDER BY rank (comme vous l'aviez) fonctionnera toujours mal pour un petit LIMIT choisir parmi un pool beaucoup plus grand de lignes qualifiantes, car il ne peut pas utiliser directement un index :l'expression sophistiquée derrière rank doit être calculé pour chaque ligne de qualification, alors tous doivent être triés avant que la petite sélection des meilleures correspondances puisse être renvoyée. C'est beaucoup, beaucoup plus cher qu'une véritable requête du plus proche voisin qui peut sélectionner directement les meilleurs résultats de l'index sans même regarder le reste.

row_number() avec une définition de fenêtre vide reflète simplement l'ordre produit par le ORDER BY du même SELECT .

Réponses associées :

Quant à votre article 3. , j'ai ajouté une réponse à la question que vous avez référencée, qui devrait l'expliquer :