あなたがそれを持っている方法で、テーブルのすべての要素と他のすべての要素の間の類似性を計算する必要があります(ほとんどクロス結合)。テーブルに1000行ある場合、条件と照合して並べ替える前に、すでに1,000,000(!)の類似性計算が行われます。ひどくスケーリングします。
代わりにSET pg_trgm.similarity_threshold
と%
演算子を使用してください。どちらもpg_trgm
モジュールによって提供されます。このように、トリグラムGiSTインデックスを使用すると大きな効果が得られます。
構成パラメーターが関数をpg_trgm.similarity_threshold
置き換え、Postgres9.6で。非推奨の関数は引き続き機能します(Postgres 13以降)。また、Postgres 9.1以降、GINおよびGiSTインデックスのパフォーマンスは多くの点で向上しました。set_limit()
show_limit()
代わりに試してください:
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;
桁違いに高速ですが、それでも低速です。
pg_trgm.similarity_threshold
は「カスタマイズされた」オプションであり、他のオプションと同じように処理できます。見る:
クロス結合の前に前提条件(最初の文字の一致など)を追加して、可能なペアの数を制限することができます(そして、機能インデックスの一致でそれをサポートします)。クロスジョインのパフォーマンスはO(N²)で低下します。
または句の出力列を参照できないため、これは機能しません。WHERE
HAVING
WHERE ... sim > 0.8
これはSQL標準(他の特定のRDBMSによってかなり緩く処理されます)に準拠しています。一方で:
ORDER BY sim DESC
とで出力列を使用できるGROUP BY
ため、機能しますORDER BY
。見る:
テストケース
古いテストサーバーでクイックテストを実行して、クレームを確認しました。
PostgreSQL9.1.4。でかかった時間EXPLAIN ANALYZE
(ベスト5)。
CREATE TEMP table t AS
SELECT some_col AS name FROM some_table LIMIT 1000; -- real life test strings
GINインデックスを使用したテストの最初のラウンド:
CREATE INDEX t_gin ON t USING gin(name gin_trgm_ops); -- round1: with GIN index
GISTインデックスを使用したテストの第2ラウンド:
DROP INDEX t_gin;
CREATE INDEX t_gist ON t USING gist(name gist_trgm_ops);
新しいクエリ:
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;
使用されたGINインデックス、64ヒット:合計実行時間:484.022ミリ秒
GISTインデックスが使用され、64ヒット:合計実行時間:248.772ミリ秒
古いクエリ:
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;
GINインデックスは使用されていません、64ヒット:合計実行時間:6345.833ミリ秒
GISTインデックスは使用されていません、64ヒット:合計実行時間:6335.975ミリ秒
それ以外は同じ結果になります。アドバイスは良いです。そしてこれはたった1000行です!
GINまたはGiST?
GINは、多くの場合、優れた読み取りパフォーマンスを提供します。
しかし、この特定のケースではありません!
これは、GiSTインデックスでは非常に効率的に実装できますが、GINインデックスでは実装できません。