Cara Anda memilikinya, kesamaan antara setiap elemen dan setiap elemen lain dari tabel harus dihitung (hampir gabungan silang). Jika tabel Anda memiliki 1000 baris, itu sudah 1.000.000 (!) perhitungan kesamaan, sebelum mereka dapat diperiksa terhadap kondisi dan diurutkan. Berskala sangat.
Gunakan SET pg_trgm.similarity_threshold
dan %
operator sebagai gantinya. Keduanya disediakan oleh pg_trgm
modul. Dengan cara ini, indeks trigram GiST dapat digunakan dengan efek yang luar biasa.
Parameter konfigurasi pg_trgm.similarity_threshold
menggantikan fungsi set_limit()
dan show_limit()
di Postgres 9.6. Fungsi yang tidak digunakan lagi masih berfungsi (pada Postgres 13). Selain itu, kinerja indeks GIN dan GiST meningkat dalam banyak hal sejak Postgres 9.1.
Coba saja:
SET pg_trgm.similarity_threshold = 0.8; -- Postgres 9.6 or later
SELECT similarity(n1.name, n2.name) AS sim, n1.name, n2.name
FROM names n1
JOIN names n2 ON n1.name <> n2.name
AND n1.name % n2.name
ORDER BY sim DESC;
Lebih cepat dengan urutan besarnya, tapi masih lambat.
pg_trgm.similarity_threshold
adalah opsi "disesuaikan", yang dapat ditangani seperti opsi lainnya. Lihat:
- Meminta parameter (pengaturan postgresql.conf) seperti "max_connections"
Anda mungkin ingin membatasi jumlah kemungkinan pasangan dengan menambahkan prasyarat (seperti mencocokkan huruf pertama) sebelum penggabungan silang (dan dukung itu dengan indeks fungsional yang cocok). Performa gabungan silang memburuk dengan O(N²) .
Ini tidak berfungsi karena Anda tidak dapat merujuk ke kolom keluaran di WHERE
atau HAVING
klausa:
WHERE ... sim > 0.8
Itu menurut standar SQL (yang ditangani agak longgar oleh RDBMS tertentu lainnya). Sebaliknya:
ORDER BY sim DESC
Karya karena kolom keluaran bisa digunakan dalam GROUP BY
dan ORDER BY
. Lihat:
- Penggunaan kembali hasil komputasi PostgreSQL dalam kueri pemilihan
Kasus uji
Saya menjalankan pengujian cepat di server pengujian lama untuk memverifikasi klaim saya.
PostgreSQL 9.1.4. Waktu yang diambil dengan EXPLAIN ANALYZE
(terbaik dari 5).
CREATE TEMP table t AS
SELECT some_col AS name FROM some_table LIMIT 1000; -- real life test strings
Tes putaran pertama dengan indeks GIN:
CREATE INDEX t_gin ON t USING gin(name gin_trgm_ops); -- round1: with GIN index
Putaran kedua tes dengan indeks GIST:
DROP INDEX t_gin;
CREATE INDEX t_gist ON t USING gist(name gist_trgm_ops);
Kueri baru:
SELECT set_limit(0.8);
SELECT similarity(n1.name, n2.name) AS sim, n1.name, n2.name
FROM t n1
JOIN t n2 ON n1.name <> n2.name
AND n1.name % n2.name
ORDER BY sim DESC;
Indeks GIN digunakan, 64 klik:total waktu proses:484.022 md
indeks GIST digunakan, 64 klik:total waktu proses:248.772 md
Permintaan lama:
SELECT (similarity(n1.name, n2.name)) as sim, n1.name, n2.name
FROM t n1, t n2
WHERE n1.name != n2.name
AND similarity(n1.name, n2.name) > 0.8
ORDER BY sim DESC;
Indeks GIN tidak digunakan, 64 klik:total waktu proses:6345.833 md
indeks GIST tidak digunakan, 64 klik:total waktu proses:6335.975 md
Jika tidak, hasil yang identik. Sarannya bagus. Dan ini untuk hanya 1000 baris !
GIN atau GiST?
GIN sering memberikan kinerja membaca yang superior:
- Perbedaan antara indeks GiST dan GIN
Tapi tidak dalam kasus khusus ini!
Ini dapat diimplementasikan dengan cukup efisien oleh indeks GiST, tetapi tidak oleh indeks GIN.
- Indeks multikolom pada 3 bidang dengan tipe data yang heterogen