2

列キーにtext_pattern_opsインデックスを持つユーザーテーブルがあります。問題は、キー列のデータにアンダースコアが含まれているため、エスケープする必要があることです。アンダースコアをエスケープする方法は2つあり(私が知っている)、そのうちの1つでのみインデックスが実際に使用されます。なぜそうなのか誰かが説明できますか?

以下の両方のクエリについて、explainanalyzeの結果を貼り付けました。

クエリ1:

EXPLAIN ANALYZE
select distinct userid from user
where userstatus IN ('Active')
and ( key like E'999999999_434153_%' or parentid = 434153) ;

クエリプラン:

HashAggregate  (cost=340685.17..340687.84 rows=267 width=4) (actual time=22678.760..22678.760 rows=0 loops=1)
  ->  Seq Scan on user  (cost=0.00..340684.50 rows=267 width=4) (actual time=22678.754..22678.754 rows=0 loops=1)
        Filter: (((userstatus)::text = 'Active'::text) AND (((key)::text ~~ '999999999_434153_%'::text) OR (parentid = 434153)))
Total runtime: 22678.879 ms

クエリ2:

EXPLAIN ANALYZE
select distinct userid from user
where userstatus IN ('Active')
and ( key like '999999999\\_434153\\_%' or parentid = 434153) ;

警告を生成します:

WARNING:  nonstandard use of \\ in a string literal
LINE 1: ...userstatus IN ('Active') and ( key like '999999999...
                                                             ^
HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.

クエリプラン:

HashAggregate  (cost=344.50..347.17 rows=267 width=4) (actual time=226.127..226.127 rows=0 loops=1)
  ->  Bitmap Heap Scan on user  (cost=11.09..343.83 rows=267 width=4) (actual time=226.123..226.123 rows=0 loops=1)
        Recheck Cond: (((key)::text ~~ '999999999\\_434153\\_%'::text) OR (parentid = 434153))
        Filter: (((userstatus)::text = 'Active'::text) AND (((key)::text ~~ '999999999\\_434153\\_%'::text) OR (parentid = 434153)))
        ->  BitmapOr  (cost=11.09..11.09 rows=84 width=0) (actual time=226.121..226.121 rows=0 loops=1)
              ->  Bitmap Index Scan on user_key_idx  (cost=0.00..5.44 rows=1 width=0) (actual time=145.758..145.758 rows=0 loops=1)
                    Index Cond: (((key)::text ~>=~ '999999999_434153_'::text) AND ((key)::text ~<~ '999999999_434153`'::text))
              ->  Bitmap Index Scan on user_parentid_key1  (cost=0.00..5.52 rows=84 width=0) (actual time=80.358..80.358 rows=0 loops=1)
                    Index Cond: (parentid = 434153)
Total runtime: 226.256 ms
4

1 に答える 1

2

あなたは2つのレベルの脱出を混乱させています。

  1. Posixスタイルのエスケープされた文字列E'foo'。の設定を確認してくださいstandard_conforming_strings

  2. LIKE演算子のパターン。ここで、_エスケープできる特別な意味があります。私はマニュアルを引用します:

    他の文字と一致せずにリテラルアンダースコアまたはパーセント記号と一致させるには、パターン内のそれぞれの文字の前にエスケープ文字を付ける必要があります。デフォルトのエスケープ文字は円記号ですが、ESCAPE句を使用して別のエスケープ文字を選択できます。エスケープ文字自体と一致させるには、2つのエスケープ文字を記述します。

インデックスは、左に固定されたパターンにのみ使用できます。パターンの中央にアンダースコア(_)がある場合、インデックスは使用できません。このパターン式のように:

key like E'999999999_434153_%'

パターンの途中でエスケープされていない場合、任意の1文字のワイルドカード-特に古いバージョンでは、で_Bツリーインデックスを使用できない場合があります。@Richardのコメントtext_pattern_opsも参照してください。

このパターンでは、_はエスケープされます。つまり、リテラルを表し_、単一文字のワイルドカードではありません->インデックスは使用されません。

key like '999999999\\_434153\\_%'

あなたが持っていると仮定しますstandard_conforming_strings = OFF。これにより、インデックスを使用しない可能性standard_conforming_strings = ONのあるリテラル\とワイルドカードを検索するパターンが生成されます。_

任意のpg_trgmをサポートするGiSTまたはGINインデックスを許可する追加モジュールに興味があるかもしれません。これについての詳細は、dba.SEの関連する回答のここここにあります LIKE

于 2012-12-10T10:30:17.717 に答える