PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Otimizando uma consulta de similaridade postgres (pg_trgm + índice gin)


Espero muito resultados mais rápidos com esta abordagem:

1.


Crie um índice GiST com 1 coluna contendo valores concatenados:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);

Isso pressupõe que todas as 3 colunas sejam definidas NOT NULL (você não especificou). Caso contrário, você precisa fazer mais.
Por que não simplificar com concat_ws() ?

2.


Use um adequado consulta, correspondendo ao índice acima:
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;

Expressões em WHERE e ORDER BY deve corresponder à expressão de índice!

Em particular ORDER BY rank (como você teve) sempre terá um desempenho ruim para um pequeno LIMIT escolher de um conjunto muito maior de linhas qualificadas, porque não pode usar um índice diretamente:a expressão sofisticada por trás de rank deve ser calculado para todo linha de qualificação, então todos devem ser classificados antes que a pequena seleção de melhores correspondências possa ser retornada. Isso é muito, muito mais caro do que uma verdadeira consulta de vizinho mais próximo que pode escolher os melhores resultados do índice diretamente sem nem mesmo olhar para o resto.

row_number() com definição de janela vazia apenas reflete a ordenação produzida pelo ORDER BY do mesmo SELECT .

Respostas relacionadas:

Quanto ao seu item 3. , adicionei uma resposta à pergunta que você fez referência, que deve explicá-la: