sql >> Base de Datos >  >> RDS >> PostgreSQL

Optimización de una consulta de similitud de postgres (pg_trgm + índice gin)

Espero mucho resultados más rápidos con este enfoque:

1.

Cree un índice GiST con 1 columna que contenga valores concatenados:

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

Esto supone que se definirán las 3 columnas NOT NULL (no especificaste). De lo contrario, debe hacer más.
¿Por qué no simplificar con concat_ws()? ?

2.

Utilice un adecuado. consulta, coincidiendo con el índice anterior:

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;

Expresiones en WHERE y ORDER BY ¡debe coincidir con la expresión del índice!

En particular ORDER BY rank (como si lo tuviera) siempre funcionará mal por un pequeño LIMIT seleccionando de un grupo mucho más grande de filas calificadas, porque no puede usar un índice directamente:la expresión sofisticada detrás de rank debe calcularse para cada fila de calificación, entonces todos deben ordenarse antes de que se pueda devolver la pequeña selección de las mejores coincidencias. Esto es mucho, mucho más caro que una verdadera consulta de vecino más cercano que puede seleccionar los mejores resultados del índice directamente sin siquiera mirar el resto.

row_number() con una definición de ventana vacía solo refleja el orden producido por ORDER BY del mismo SELECT .

Respuestas relacionadas:

En cuanto a su artículo 3. , agregué una respuesta a la pregunta a la que hizo referencia, eso debería explicarlo: