sql >> Databasteknik >  >> RDS >> PostgreSQL

Optimera en postgres likhetsfråga (pg_trgm + gin index)

Jag förväntar mig mycket snabbare resultat med detta tillvägagångssätt:

1.

Skapa ett GiST-index med en kolumn som innehåller sammanlänkade värden:

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

Detta förutsätter att alla tre kolumnerna är definierade NOT NULL (du angav inte). Annars måste du göra mer.
Varför inte förenkla med concat_ws() ?

2.

Använd en riktig fråga som matchar ovanstående 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;

Uttryck i WHERE och ORDER BY måste matcha indexuttryck!

I synnerhet ORDER BY rank (som du hade det) kommer alltid att fungera dåligt för en liten LIMIT plocka från en mycket större pool av kvalificerande rader, eftersom den inte kan använda ett index direkt:Det sofistikerade uttrycket bakom rank måste beräknas för varje kvalificeringsraden måste alla sorteras innan det lilla urvalet av bästa matcher kan returneras. Det här är mycket, mycket dyrare än en äkta fråga om närmaste granne som kan välja de bästa resultaten från indexet direkt utan att ens titta på resten.

row_number() med tomt fönster återspeglar definitionen bara ordningen som produceras av ORDER BY av samma SELECT .

Relaterade svar:

När det gäller din artikel 3. , Jag lade till ett svar på frågan du hänvisade till, som borde förklara det:




  1. Databasdesign:1 tabell eller 2?

  2. Postgres-vyer känns inte igen av rspec

  3. convert_tz returnerar null

  4. mysql returtabellnamn