94

私は「気にしないでLIKE」と~代わりに使うように指示されました。何が問題でLIKE、どのように~違うのですか?

この文脈で名前がありますか~、それとも人々は「チルダ演算子を使用してください」と言いますか?

4

7 に答える 7

74

~は正規表現演算子であり、それによって示される機能があります。正規表現のワイルドカードと数量詞の全範囲を指定できます。詳細については、ドキュメントを参照してください。それは確かにより強力でありLIKE、その力が必要なときに使用する必要がありますが、それらは異なる目的を果たします。

于 2012-09-17T02:16:06.550 に答える
44

何も悪いことはなくLIKE、IMO、それを支持~する理由はありません。むしろ反対です。LIKESQL標準です。ですがSIMILAR TO、広くサポートされていません。PostgreSQL ~ operator(またはposix正規表現マッチング演算子)はSQL標準ではありません。

そのため、表現力に富んだ場所で使用することを好み、完全な正規表現の能力が必要な場合にLIKEのみ使用します。~データベースを移植する必要がある場合、害を及ぼすことは1つ少なくなります。私は十分に強力でないSIMILAR TOときに使用する傾向がありましたが、アーウィンのコメントの後、私はそれをやめ、仕事をしないときに使用すると思います。LIKE~LIKE

また、PostgreSQLはプレフィックス検索にb-treeインデックスを使用できます(たとえば、データベースがロケールにあるか、インデックスにが含まれている場合LIKE 'TEST%')。以前に書いたものとは異なり、Pgは左アンカーのposix正規表現にこのようなインデックスを使用することもできます。明示的な「^ TEST。*」が必要なだけなので、正規表現は最初からしか一致しません。以前の私の投稿では、プレフィックス検索にインデックスを使用できないと誤って述べていました。その違いがなくなると、可能な限り標準に準拠した機能を使い続けるかどうかにかかっています。LIKESIMILAR TOCtext_pattern_ops~

このデモを参照してくださいSQLFiddle ; さまざまな実行プランに注意してください。との違いに注意して~ '1234.*'ください~ '^1234.*'

与えられたサンプルデータ:

create table test (
   blah text
);
insert into test (blah)  select x::text from generate_series(1,10000) x;
create index test_blah_txtpat_idx ON test(blah text_pattern_ops);

インデックスを使用している間は代替手段がないため、~かなり高価な場合でも(人為的にそうのために)、seqscanを使用することに注意してください。ただし、左アンカーで修正すると、インデックスも使用されます。enable_seqscanLIKE~

regress=# SET enable_seqscan = 'f';
SET
regress=# explain select 1 from test where blah ~ '12.*';
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Seq Scan on test  (cost=10000000000.00..10000000118.69 rows=2122 width=0)
   Filter: (blah ~ '12.*'::text)
(2 rows)
regress=# explain select 1 from test where blah like '12%';
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=4.55..46.76 rows=29 width=0)
   Filter: (blah ~~ '12%'::text)
   ->  Bitmap Index Scan on test_blah_txtpat_idx  (cost=0.00..4.54 rows=29 width=0)
         Index Cond: ((blah ~>=~ '12'::text) AND (blah ~<~ '13'::text))
(4 rows)
regress=# explain select 1 from test where blah ~ '^12.*';
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=5.28..51.53 rows=101 width=0)
   Filter: (blah ~ '^12.*'::text)
   ->  Bitmap Index Scan on test_blah_txtpat_idx  (cost=0.00..5.25 rows=100 width=0)
         Index Cond: ((blah ~>=~ '12'::text) AND (blah ~<~ '13'::text))
(4 rows)
于 2012-09-17T02:32:46.803 に答える
40

概要

LIKESIMILAR TOおよび~はPostgreSQLの基本的なパターンマッチング演算子です。

LIKE可能であれば、 ( )を使用する~~と、最も速くて簡単です。
できない場合は、正規表現(~)を使用すると、より強力になります。
決して使用しないでくださいSIMILAR TO。それは無意味です。下記参照。

追加モジュールpg_trgmをインストールすると、高度なインデックスオプションと類似性演算子%が追加されます。また、独自のインフラストラクチャと演算子(とりわけ)を使用したテキスト検索
もあります。@@

インデックスのサポートは、これらの演算子のそれぞれで利用できます-程度はさまざまです。それは定期的に他のオプションのパフォーマンスよりも優先されます。ただし、インデックスを使用した場合でも、詳細には多くの余裕があります。

インデックスのサポート

pg_trgmがない場合、左アンカー検索パターンのインデックスサポートのみがありデータベースクラスターが非Cロケールで実行されている場合(通常の場合)、またはのような特別な演算子クラスを持つインデックスが必要です。これにより、基本的な左アンカー正規表現もサポートされます。例:text_pattern_opsvarchar_pattern_ops

CREATE TABLE tbl(string text);

INSERT INTO  tbl(string)
SELECT x::text FROM generate_series(1, 10000) x;

CREATE INDEX tbl_string_text_pattern_idx ON tbl(string text_pattern_ops);

SELECT * FROM tbl WHERE string ~ '^1234';  -- left anchored pattern

ここでdb<>フィドル

pg_trgmがインストールされている場合、GINまたはGiSTインデックスは演算子クラスgist_trgm_opsまたはgin_trgm_opsます。これらのインデックスは、固定されたままではなく、任意の式をサポートします。 LIKEそして、マニュアルを引用すると:

PostgreSQL 9.3以降、これらのインデックスタイプは、正規表現の一致のインデックス検索もサポートします。

詳細:


SIMILAR TO非常に奇妙な構成です。PostgreSQLは、SQL標準の初期バージョンで定義されているため、これを実装するだけです。内部的には、すべてのSIMILAR TO式が正規表現で書き直されます。したがって、任意の式に対して、同じジョブをより高速SIMILAR TOに実行する正規表現が少なくとも1つあります。私は決して使用しません。SIMILAR TO

参考文献:

于 2012-09-17T12:57:02.827 に答える
7

演算子は~~と同等LIKEです。 ~一方、POSIX正規表現を使用して一致します

于 2012-09-17T02:15:40.807 に答える
6

インデックスが含まれていない場合の2つの演算子のパフォーマンスの違いを確認するために、すばやく簡単なベンチマークを実行しました。

postgres=# \timing
Timing is on.
postgres=# SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text LIKE '%5%') AS x;
  count
─────────
 5217031
(1 row)

Time: 5631.662 ms
postgres=# SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text ~ '5') AS x;
  count
─────────
 5217031
(1 row)

Time: 10612.406 ms

この例では、LIKEオペレーターはオペレーターのほぼ2倍の速度~です。LIKEしたがって、速度が重要である場合、時期尚早に最適化しないように注意してくださいが、私はに傾くでしょう。~より多くの柔軟性を提供します。

興味のある方のEXPLAINために、上記のクエリの計画を以下に示します。

postgres=# EXPLAIN ANALYZE SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text LIKE '%5%') AS x;
                                                              QUERY PLAN
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 Aggregate  (cost=20.00..20.01 rows=1 width=0) (actual time=9967.748..9967.749 rows=1 loops=1)
   ->  Function Scan on generate_series x  (cost=0.00..17.50 rows=1000 width=0) (actual time=1732.084..7404.755 rows=5217031 loops=1)
         Filter: ((val)::text ~~ '%5%'::text)
         Rows Removed by Filter: 4782969
 Total runtime: 9997.587 ms
(5 rows)

postgres=# EXPLAIN ANALYZE SELECT count(1) FROM (SELECT val from generate_series(1, 10000000) x(val) WHERE val::text ~ '5') AS x;
                                                              QUERY PLAN
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 Aggregate  (cost=20.00..20.01 rows=1 width=0) (actual time=15118.061..15118.061 rows=1 loops=1)
   ->  Function Scan on generate_series x  (cost=0.00..17.50 rows=1000 width=0) (actual time=1724.591..12516.996 rows=5217031 loops=1)
         Filter: ((val)::text ~ '5'::text)
         Rows Removed by Filter: 4782969
 Total runtime: 15147.950 ms
(5 rows)
于 2015-03-06T19:33:41.833 に答える
6

Likeは、文字列の最初または最後または中間の一部と一致しているだけです。傾斜(〜)は正規表現と一致しています。

これをさらに説明するために、テーブルを作成していくつかの値を挿入しましょう

# create table users(id serial primary key, name character varying);

それでは、テーブルにいくつかの値を挿入しましょう

# insert into users (name) VALUES ('Alex'), ('Jon Snow'), ('Christopher'), ('Arya'),('Sandip Debnath'), ('Lakshmi'),('alex@gmail.com'),('@sandip5004'), ('lakshmi@gmail.com');

これで、テーブルは次のようになります。

 id |       name        
----+-------------------
  1 | Alex
  2 | Jon Snow
  3 | Christopher
  4 | Arya
  5 | Sandip Debnath
  6 | Lakshmi
  7 | alex@gmail.com
  8 | lakshmi@gmail.com
  9 | @sandip5004

ケースライク

# select * from users where name like 'A%';
 id | name 
----+------
  1 | Alex
  4 | Arya
(2 rows)

ご覧 のとおり'A%'、名前が大文字のAで始まる値のみが取得されます。

# select * from users where name like '%a%';
 id |       name        
----+-------------------
  4 | Arya
  5 | Sandip Debnath
  6 | Lakshmi
  7 | alex@gmail.com
  8 | lakshmi@gmail.com

ご覧 のとおり'%a%'、名前が名前の間にある値のみが取得aされます。

# select * from users where name like '%a';

 id | name 
----+------
  4 | Arya

ご覧 のとおり'%a'、名前が。で終わる値のみが取得されaます。

ケース〜(傾き)

# select * from users where name ~* 't';
 id |      name      
----+----------------
  3 | Christopher
  5 | Sandip Debnath

ご覧 のとおりname ~* 't'、名前が。の値のみが取得されますt~大文字と小文字を区別し、〜*は大文字と小文字を区別しないことを意味します。

# select * from users where name ~ 'T';
 id | name 
----+------
(0 rows)

上記のクエリではT、どのエントリとも一致しなかったため、0行が返されました

ここで、電子メールIDを取得するだけで、メールIDが何であるかはわからないが、電子メールのパターンはわかっている、つまり文字または数字、または_または。が存在する場合を考えてみましょう。または-そして@そしてさらにいくつかの文字または数字または-そして。次に、comまたはinまたはorg etc、正規表現を使用してパターンを作成できます。

次に、正規表現を使用して結果をフェッチしてみましょう

# select * from users where name ~* '[a-z0-9\.\-\_]+@[a-z0-9\-]+\.[a-z]{2,5}';
 id |       name        
----+-------------------
  7 | alex@gmail.com
  8 | lakshmi@gmail.com

同様に、間にスペースがあるいくつかの名前をフェッチできます

#select * from users where name ~* '[a-z]+\s[a-z]+';
 id |      name      
----+----------------
  2 | Jon Snow
  5 | Sandip Debnath

[az] +は、aからzまでの任意の文字が存在する可能性があることを意味し、+は、1回以上発生する可能性があることを意味し、\ sは、その後にスペースがあり、その後、1回以上発生する可能性のある文字のセットがあることを意味します。回数。

この詳細な分析がお役に立てば幸いです。

于 2018-08-30T15:15:05.577 に答える
3

はい、POSIX正規表現の略です。もう1つの方法は、「SIMILAR TO」演算子を使用して正規表現にSQL標準アプローチを使用することです。ただし、提供される機能のセットは限られていますが、理解しやすい場合があります。これはdba交換からの良いリファレンスだと思います: https ://dba.stackexchange.com/questions/10694/pattern-matching-with-like-similar-to-or-regular-expressions-in-postgresql

于 2012-09-17T02:32:27.940 に答える