web-dev-qa-db-ja.com

式の集計LIKEクエリを高速化するためにインデックスを作成する方法は?

タイトルに間違った質問をしているのかもしれません。事実は次のとおりです。

私のカスタマーサービス担当者は、Djangoベースのサイトの管理インターフェイスでカスタマールックアップを実行すると、応答時間が遅いという不満を言っています。

Postgres 8.4.6を使用しています。私は遅いクエリのロギングを開始し、この原因を発見しました:

SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')

このクエリの実行には32秒以上かかります。 EXPLAINが提供するクエリプランは次のとおりです。

QUERY PLAN
Aggregate  (cost=205171.71..205171.72 rows=1 width=0)
  ->  Seq Scan on auth_user  (cost=0.00..205166.46 rows=2096 width=0)
        Filter: (upper((email)::text) ~~ '%DEYK%'::text)

これはDjango ORMからDjango QuerySetがDjango管理アプリケーションによって生成されたクエリ自体を制御することはできません。インデックスは論理的なソリューションのようです。これを高速化するためにインデックスを作成しようとしましたが、違いはありませんでした。

CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))

何が悪いのですか?このクエリを高速化するにはどうすればよいですか?

22
David Eyk

PostgreSQL 8.4ではLIKE/ILIKEのインデックスサポートはありません- 左アンカー検索を除く)用語

PostgreSQL 9.1以降、追加モジュール pg_trgm は、LIKE/ILIKEまたは正規表現をサポートするGINおよびGistトライグラムインデックスの演算子クラスを提供します(演算子~ と友達)。データベースごとに1回インストールします。

CREATE EXTENSION pg_trgm;

GINインデックスの例:

CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);

関連:

24

一致の先頭に「%」があるため、そのインデックスは役に立ちません-BTREEインデックスは接頭辞にのみ一致でき、クエリの先頭のワイルドカードは検索する固定接頭辞がないことを意味します。

そのため、テーブルスキャンを実行し、すべてのレコードをクエリ文字列と照合します。

現在のLIKEで部分文字列検索を行うのではなく、フルテキストインデックスとテキストマッチング演算子を使用することを検討する必要があるでしょう。全文検索の詳細については、ドキュメントをご覧ください。

http://www.postgresql.org/docs/8.4/static/textsearch-intro.html

実際、そのページから、LIKEは明らかにインデックスを使用しないことに気づきました。BTREEインデックスを使用して非ワイルドカードプレフィックスを解決できるはずなので、奇妙に思えます。いくつかの簡単なテストは、ドキュメントがおそらく正しいことを示唆していますが、その場合、LIKEを使用してクエリを解決している間は、大量のインデックスは役に立ちません。

9
TomH