132

LIKEデータベース内の特定のテーブルへのクエリに関して、応答時間にかなりのばらつきが見られます。200〜400ミリ秒以内に結果が得られる場合もありますが(非常に許容範囲内)、結果が返されるまでに30秒ほどかかる場合もあります。

LIKEクエリは非常にリソースを消費することは理解していますが、応答時間にこれほど大きな違いがある理由がわかりません。フィールドにbtreeインデックスを作成しましたが、クエリには役立たowner1ないと思います。LIKE誰かアイデアはありますか?

サンプルSQL:

SELECT gid, owner1 FORM parcels
WHERE owner1 ILIKE '%someones name%' LIMIT 10

私も試しました:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%') LIMIT 10

と:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('someones name%') LIMIT 10

同様の結果が得られました。
テーブルの行数:約95,000。

4

8 に答える 8

329

FTSはサポートしていませんLIKE

以前に受け入れられた答えは正しくありませんでした。全文索引を使用した全文検索は、演算子用ではありませLIKEん。独自の演算子があり、任意の文字列に対しては機能しません。辞書とステミングに基づいた単語で動作します。単語のプレフィックスマッチングサポートしていますが、演算子はサポートしていません。LIKE

のトリグラムインデックスLIKE

左アンカーのパターンだけでなく、すべてパターンをサポートするGINおよびGiSTトリグラムインデックスpg_trgmのオペレータークラスを提供する追加モジュールをインストールします。LIKEILIKE

インデックスの例:

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

または:

CREATE INDEX tbl_col_gist_trgm_idx ON tbl USING gist (col gist_trgm_ops);

クエリの例:

SELECT * FROM tbl WHERE col LIKE '%foo%';   -- leading wildcard
SELECT * FROM tbl WHERE col ILIKE '%foo%';  -- works case insensitively as well

トリグラム?短い文字列はどうですか?

インデックス値の文字が3文字未満の単語は引き続き機能します。マニュアル:

文字列に含まれるトリグラムのセットを決定するとき、各単語には接頭辞2つのスペースと接尾辞1つのスペースがあると見なされます。

そして、3文字未満の検索パターン?マニュアル:

正規表現検索と正規表現検索の両方LIKEで、抽出可能なトリグラムのないパターンは、フルインデックススキャンに縮退することに注意してください。

つまり、インデックス/ビットマップインデックススキャンは引き続き機能し(プリペアドステートメントのクエリプランは機能しません)、パフォーマンスが向上することはありません。1文字または2文字の文字列はほとんど選択的ではなく(基になるテーブルの数パーセント以上が一致する)、全表スキャンの方が高速であるため、インデックスのサポートによって最初からパフォーマンスが向上しないため、通常は大きな損失はありません。

text_pattern_opsまたはCOLLATE "C"プレフィックスマッチング用

アップデート

Postgres 9.1以降、COLLATE "C"より優れています。見る:

元の回答

左に固定されたパターン(先頭のワイルドカードなし)の場合、btreeインデックスに適した演算子クラスtext_pattern_opsを使用して最適化を取得します:またはvarchar_pattern_ops。標準のPostgresの両方の組み込み機能であり、追加のモジュールは必要ありません。同様のパフォーマンスですが、インデックスははるかに小さくなります。

インデックスの例:

CREATE INDEX tbl_col_text_pattern_ops_idx ON tbl(col text_pattern_ops);

クエリの例:

SELECT * FROM tbl WHERE col LIKE 'foo%';  -- no leading wildcard

または「C」ロケール(事実上ロケールなし)でデータベースを実行する必要がある場合は、とにかくすべてがバイト順序に従ってソートされ、デフォルトの演算子クラスを持つプレーンなbtreeインデックスがその役割を果たします。


参考文献

于 2012-11-19T11:08:55.103 に答える
10

おそらく、高速なものは、インデックスを使用できるように大文字と小文字を区別するアンカーパターンです。つまり、一致文字列の先頭にワイルドカードがないため、エグゼキュータはインデックス範囲スキャンを使用できます。(ドキュメント内の関連するコメントはここにあります)Lowerおよびilikeも、その目的のために特別にインデックスを作成しない限り、インデックスを使用する能力を失います(機能インデックスを参照)。

フィールドの中央で文字列を検索する場合は、全文またはトリグラムインデックスを調べる必要があります。それらの最初はPostgresコアにあり、もう1つはcontribモジュールで利用できます。

于 2009-10-14T14:43:35.967 に答える
4

PostgreSQLの別のタイプのインデックスであるWildspeedをインストールできます。Wildspeedは%word%ワイルドカードで機能します。問題ありません。欠点はインデックスのサイズです。これは大きくなる可能性があり、非常に大きくなる可能性があります。

于 2010-02-25T21:36:31.290 に答える
4

最近、200000レコードを含むテーブルで同様の問題が発生し、LIKEクエリを繰り返す必要があります。私の場合、検索対象の文字列が修正されました。他の分野はさまざまでした。そのため、私は書き直すことができました:

SELECT owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%');

なので

CREATE INDEX ix_parcels ON parcels(position(lower('someones name') in lower(owner1)));

SELECT owner1 FROM parcels
WHERE position(lower('someones name') in lower(owner1)) > 0;

クエリがすぐに戻ってきて、インデックスが次のように使用されていることを確認したとき、私は嬉しかったですEXPLAIN ANALYZE

 Bitmap Heap Scan on parcels  (cost=7.66..25.59 rows=453 width=32) (actual time=0.006..0.006 rows=0 loops=1)
   Recheck Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
   ->  Bitmap Index Scan on ix_parcels  (cost=0.00..7.55 rows=453 width=0) (actual time=0.004..0.004 rows=0 loops=1)
         Index Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
 Planning time: 0.075 ms
 Execution time: 0.025 ms
于 2018-11-21T23:10:01.947 に答える
4

LIKE、ILIKE、upper、lowerなどの関数を含む列で句を使用する場合は常に、postgresは通常のインデックスを考慮しません。各行を通過するテーブルのフルスキャンを実行するため、速度が低下します。

正しい方法は、クエリに従って新しいインデックスを作成することです。たとえば、大文字と小文字を区別せずに列を一致させたい場合、列はvarcharです。次に、このように行うことができます。

create index ix_tblname_col_upper on tblname (UPPER(col) varchar_pattern_ops);

同様に、列がテキストの場合は、次のようにします

create index ix_tblname_col_upper on tblname (UPPER(col) text_pattern_ops);

同様に、関数の上位を必要な他の関数に変更できます。

于 2019-09-18T13:56:39.870 に答える
3

postgresqlでのLIKEクエリのパフォーマンスを向上させるには、以下のクエリを実行してください。大きなテーブルには、次のようなインデックスを作成します。

CREATE INDEX <indexname> ON <tablename> USING btree (<fieldname> text_pattern_ops)
于 2017-10-11T11:40:39.807 に答える
1

Django ORMは、大文字と小文字を区別しないようにUPPER(text)、すべてのクエリに使用する傾向があります。LIKE

にインデックスを追加するUPPER(column::text)と、他のものとは異なり、システムが大幅に高速化されました。

%をリードする限り、はい、それはインデックスを使用しません。すばらしい説明については、このブログを参照してください。

https://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning

于 2018-09-20T14:55:25.063 に答える
0

同様のクエリでは、作成したインデックスを使用できない可能性があります。理由は次のとおりです。

1)LIKE基準はワイルドカードで始まります。

2)LIKE基準で関数を使用しました。

于 2009-10-14T14:45:09.203 に答える