なぜですか?
クエリはプリンシパルのインデックスを使用できません。テーブルのlocations
にインデックスが必要になります 、しかしあなたが持っているものはテーブルaddresses
にあります 。
次の設定で私の主張を確認できます:
SET enable_seqscan = off;
(セッションのみ、デバッグのみ。本番環境では絶対に使用しないでください。)インデックスがシーケンシャルスキャンよりも高価になるわけではなく、Postgresがクエリに使用する方法はまったくありません 。
余談:[INNER] JOIN ... ON true
CROSS JOIN ...
の厄介な言い方です
ORDER
を削除した後にインデックスが使用されるのはなぜですか およびLIMIT
?
Postgresはこの単純なフォームを次のように書き換えることができるため:
SELECT *
FROM addresses a
JOIN locations l ON a.address ILIKE '%' || l.postalcode || '%';
まったく同じクエリプランが表示されます。 (少なくとも、Postgres 9.5でのテストでは行います。)
ソリューション
locations.postalcode
にインデックスが必要です 。そして、LIKE
を使用している間 またはILIKE
また、インデックス付きの式(postalcode
)を持参する必要があります )左 オペレーターの側。 ILIKE
演算子~~*
で実装されます この演算子にはCOMMUTATOR
がありません (論理的に必要)、したがって、オペランドを反転させることはできません。これらの関連する回答の詳細な説明:
- PostgreSQLは配列列にインデックスを付けることができますか?
- PostgreSQL-テキスト配列 に類似した値が含まれています
- 正規表現パターンを含むテキスト列に便利なインデックスを付ける方法はありますか?
解決策は、トリグラム類似性演算子 %
またはその逆、距離演算子<->
最も近い隣人で 代わりにクエリを実行します(それぞれがそれ自体の整流子であるため、オペランドは場所を自由に切り替えることができます):
SELECT *
FROM addresses a
JOIN LATERAL (
SELECT *
FROM locations
ORDER BY postalcode <-> a.address
LIMIT 1
) l ON address ILIKE '%' || postalcode || '%';
最も類似したpostalcode
を見つける addresses
ごとに 、次にそのpostalcode
かどうかを確認します 実際には完全に一致します。
このように、より長いpostalcode
短いpostalcode
よりも類似している(距離が短い)ため、自動的に優先されます それも一致します。
少し不確実性が残っています。考えられる郵便番号によっては、文字列の他の部分のトリグラムが一致するために誤検知が発生する可能性があります。質問には、詳細を述べるのに十分な情報がありません。
ここ 、[INNER] JOIN
CROSS JOIN
の代わりに 実際の結合条件を追加するので、理にかなっています。
だから:
CREATE INDEX locations_postalcode_trgm_gist_idx ON locations
USING gist (postalcode gist_trgm_ops);