Очакваммного по-бързи резултати с този подход:
1.
Създайте GiST индекс с 1 колона, съдържаща свързани стойности:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);
Това предполага, че всичките 3 колони са дефинирани NOT NULL
(не сте посочили). В противен случай трябва да направите повече.
Защо не опростите с concat_ws()
?
- Комбинирайте две колони и добавете в една нова колона
- По-бърза заявка със съпоставяне на шаблони в множество текстови полета
- Комбинирайте две колони и добавете в една нова колона
2.
Използвайте подходящ nearest-neighbor заявка, съответстваща на горния индекс:
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;
Изрази в WHERE
и ORDER BY
трябва да съответства на индексния израз!
По-специално ORDER BY rank
(както го имахте) винаги ще работи лошо за малък LIMIT
избиране от много по-голям набор от отговарящи на изискванията редове, тъй като не може да използва директно индекс:Сложният израз зад rank
трябва да се изчислява за всеки квалифициращ ред, тогава всички трябва да бъдат сортирани, преди малката селекция от най-добри съвпадения да може да бъде върната. Това е много, много по-скъпо отколкото истинска заявка за най-близък съсед, която може да избере най-добрите резултати от индекса директно, без дори да гледа останалите.
row_number()
с празна дефиниция на прозорец просто отразява подреждането, създадено от ORDER BY
от същия SELECT
.
Свързани отговори:
Що се отнася до вашия артикул 3.
, добавих отговор към посочения от вас въпрос, който трябва да го обясни: