Saya berharap banyak hasil yang lebih cepat dengan pendekatan ini:
1.
Buat indeks GiST dengan 1 kolom yang berisi nilai gabungan:
CREATE INDEX users_search_idx ON auth_user
USING gist((username || ' ' || first_name || ' ' || last_name) gist_trgm_ops);
Ini mengasumsikan semua 3 kolom didefinisikan NOT NULL
(Anda tidak menentukan). Jika tidak, Anda perlu melakukan lebih banyak.
Mengapa tidak menyederhanakan dengan concat_ws()
?
- Gabungkan dua kolom dan tambahkan menjadi satu kolom baru
- Kueri lebih cepat dengan pencocokan pola di beberapa bidang teks
- Gabungkan dua kolom dan tambahkan menjadi satu kolom baru
2.
Gunakan nearest-neighbor yang tepat kueri, cocok dengan indeks di atas:
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;
Ekspresi dalam WHERE
dan ORDER BY
harus cocok dengan ekspresi indeks!
Khususnya ORDER BY rank
(seperti yang Anda miliki) akan selalu berkinerja buruk untuk LIMIT
kecil memilih dari kumpulan baris kualifikasi yang jauh lebih besar, karena tidak dapat menggunakan indeks secara langsung:Ekspresi canggih di balik rank
harus dihitung untuk setiap baris kualifikasi, maka semua harus diurutkan sebelum pilihan kecil pertandingan terbaik dapat dikembalikan. Ini jauh, jauh lebih mahal daripada kueri tetangga terdekat yang sebenarnya yang dapat memilih hasil terbaik dari indeks secara langsung bahkan tanpa melihat sisanya.
row_number()
dengan definisi jendela kosong hanya mencerminkan pemesanan yang dihasilkan oleh ORDER BY
dari SELECT
. yang sama .
Jawaban terkait:
Adapun item Anda 3.
, saya menambahkan jawaban untuk pertanyaan yang Anda rujuk, yang seharusnya menjelaskannya: