sql >> Databáze >  >> RDS >> PostgreSQL

Optimalizace postgresového dotazu na podobnost (pg_trgm + gin index)

Očekávám hodně rychlejší výsledky s tímto přístupem:

1.

Vytvořte index GiST s 1 sloupcem obsahujícím zřetězené hodnoty:

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

To předpokládá, že všechny 3 sloupce budou definovány NOT NULL (neuvedl jste). Jinak musíte udělat víc.
Proč nezjednodušit pomocí concat_ws() ?

2.

Použijte správný dotaz odpovídající výše uvedenému indexu:

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;

Výrazy v WHERE a ORDER BY musí odpovídat výrazu indexu!

Zejména ORDER BY rank (jako byste to měli vy) bude vždy fungovat špatně za malý LIMIT výběr z mnohem většího fondu kvalifikačních řádků, protože nemůže přímo použít index:sofistikovaný výraz za rank se musí počítat pro každý kvalifikační řadě, pak musí být všechny seřazeny, než bude možné vrátit malý výběr nejlepších zápasů. To jemnohem, mnohem dražší než skutečný dotaz na nejbližšího souseda, který dokáže vybrat nejlepší výsledky z indexu přímo, aniž by se musel dívat na zbytek.

row_number() s definicí prázdného okna pouze odráží řazení vytvořené ORDER BY stejného SELECT .

Související odpovědi:

Pokud jde o vaši položku 3. , přidal jsem odpověď na otázku, na kterou jste odkazoval, která by to měla vysvětlit:




  1. Překlad Microsoft T-SQL do Oracle SQL

  2. Nelze se připojit k Oracle pomocí PDO

  3. Získejte mysqldump pro výpis dat vhodných pro vstup psql (uvozené jednoduché uvozovky)

  4. Priorita operátorů v regulárních výrazech