1. ホーム
  2. データベース
  3. ポストグレスキュー

PostgreSQLのデータベースでLIKE文の効率を確保する方法(推奨)

2022-01-21 23:17:03

どんなデータベースでもLIKE文の使用は頭を悩ませることが多い。多くのユーザーはLIKE文の実行効率が非常に低く、実行計画を確認した後、インデックスされていないことに気づくからだ。ではPostgresqlデータにおけるLIKE文の実行効率はどうだろうか。どうすればLIKE文の実行効率を向上させることができるのでしょうか?

  実験環境

データベース環境 PostgreSQL 12.3 X86_64  

仮想環境を作成します。

postgres=# create database testdb01 owner highgo;
CREATE DATABASE
postgres=# \c testdb01 highgo
 
 
testdb01=# create table testliketb01 (userid int primary key,username varchar(20),password varchar(60),description text);
CREATE TABLE

このテストがより直感的であることを確認するために、テーブルにランダムなデータを入力してみましょう。

testdb01=# insert into testliketb01 select generate_series(1,500000),split_part('Zhang San,Li Si,Wang Wu,Xiao Ming,Xiao Hong',',',',(random()*(5-1)+1)::int),md5(( random()*(5-1)+1)::varchar),split_part('highgo,highgo02,highgo03',','',(random()*(3-1)+1)::int);

  この時点で、仮想データが作成されます。

testdb01=# select * from testliketb01 limit 10;
userid | username | password | description
--------+----------+----------------------------------+-------------
      1 | wangwu | 4f2bca371b42abd1403d5c20c4542dff | highgo
      2 | Li Si | 2a978c605188770c5ed162889fff189e | highgo02
      3 | Li Si | f5d129ab728b72ac6f663fe544bc7c16 | highgo
      4 | 小明 | 53134fa1022c58e65168b6aa1fbe5e39 | highgo02
      5 | 王五 | 2cf9abb2a8b676a626fa2c317d401ed8 | highgo02
      6 | 王五 | 2247a0cfda1f2819554d6e8e454622eb | highgo02
      7 | Zhang San | 59dfdc680c17533dfba1c72c9ce0bf76 | highgo02
      8 | wangwu | 87db4258236a3826259dcc3e7cb5fc63 | highgo02
      9 | wangwu | baaf7a2f7027df9aaeb665121432b6e2 | highgo02
     10 | wangwu | 2f8fb36b3227c795b111b9bd5b031a76 | highgo02
(10 rows)
The status of the database at this point.
testdb01=# \l+ testdb01
                                                List of databases
   Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
----------+--------+----------+-------------+-------------+-------------------+-------+------------+-------------
testdb01 | highgo | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 59 MB | pg_default |
(1 row)

  シンプルなLIKE文のクエリです。

testdb01=# explain analyze select * from testliketb01 where username like 'Wang%';
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
Seq Scan on testliketb01 (cost=0.00..11405.00 rows=125350 width=52) (actual time=0.014..177.571 rows=124952 loops=1)
   Filter: ((username)::text ~~ 'Wang%'::text)
   Rows Removed by Filter: 375048
Planning Time: 0.121 ms
Execution Time: 190.554 ms
(5 rows)

結論 LIKEクエリがインデックスを通過しなかった 通常のインデックスを作成する: testdb01=# create index idx_testliketb01_username on testliketb01(username); CREATE INDEX 3回実行する。analyze testliketb01 ; re LIKE文を実行し、それがまだインデックスを通過しないことを見つける オペレータクラスを含むインデックスを作成する: testdb01=# create index idx_testliketb01_username on testliketb01(username varchar_pattern_ops); CREATE INDEX three times実行:分析テストリケットベ01を ;    

testdb01=# explain analyze select * from testliketb01 where username like 'Wang%';
                                                                   QUERY PLAN                                                                    
---------------------------------------------------------------------------------------------------------------------------------- ---------------
Bitmap Heap Scan on testliketb01 (cost=2665.26..9387.14 rows=125350 width=52) (actual time=31.383..94.745 rows=124952 loops=1)
   Filter: ((username)::text ~~ 'Wang%'::text)
   Heap Blocks: exact=5155
   -> Bitmap Index Scan on idx_testliketb01_username (cost=0.00..2633.92 rows=125350 width=0) (actual time=29.730..29.730 rows=124952 loops=1)
         Index Cond: (((username)::text ~>=~ 'king'::text) AND ((username)::text ~<~ 'cemetery'::text))
Planning Time: 0.111 ms
Execution Time: 107.030 ms
(7 rows)

結論 通常のインデックスを作成し、統計情報を収集した後、LIKE文を実行すると、データベースはまだインデックスを使用できない場合があります。操作クラス付きのインデックスを作成し、統計情報を収集した後、LIKE文を実行すると、インデックスの正常な利用が確認でき、実行効率が大幅に改善された。  

追記:operator classは、Postgresqlの新バージョンにおけるインデックス作成の新しいオプションで、インデックスをoperator classにすることで、より正確に統計情報を収集するように設計されています。

  より正確に統計情報を収集するために、データベースの初期化や作成時にCollateを"C"に設定することも、Postgresqlのデータではよくある最適化です。   では、Collateを"C"に設定した場合の効果を検証してみましょう。

testdb01=# create database testdb02 with TEMPLATE template0 LC_COLLATE='C' LC_CTYPE ='C' owner highgo;
CREATE DATABASE
 
 
testdb02=# \l+ testdb02
                                           List of databases
   Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
----------+--------+----------+---------+-------+-------------------+-------+------------+-------------
testdb02 | highgo | UTF8 | C | C | | 59 MB | pg_default |
(1 row)
 
 
testdb02=# create index idx_testliketb01_username on testliketb01(username);
CREATE INDEX
testdb02=# analyze testliketb01 ;
ANALYZE
testdb02=# analyze testliketb01 ;
ANALYZE
testdb02=# analyze testliketb01 ;
ANALYZE
testdb02=# explain analyze select * from testliketb01 where username like 'Wang%';
                                                                   QUERY PLAN                                                                    
---------------------------------------------------------------------------------------------------------------------------------- ---------------
Bitmap Heap Scan on testliketb01 (cost=2680.26..9410.67 rows=126033 width=52) (actual time=35.262..99.052 rows=124992 loops=1)
   Filter: ((username)::text ~~ 'Wang%'::text)
   Heap Blocks: exact=5155
   -> Bitmap Index Scan on idx_testliketb01_username (cost=0.00..2648.75 rows=126033 width=0) (actual time=33.920..33.920 rows=124992 loops=1)
         Index Cond: (((username)::text >= 'king'::text) AND ((username)::text < 'naming'::text))
Planning Time: 0.276 ms
Execution Time: 111.578 ms
(7 rows)

結論 データベース作成時に Collate を "C" に設定すると、LIKE 文はインデックスが通常のインデックスであっても、そのインデックスを使用してクエリ効率を向上させることができるようになります。    

最適化の提案

1. データベースの初期化または作成時に、照合順序を "C" に設定します。

2、インデックス作成時に、インデックスの操作クラスを指定する。(text_pattern_ops, varchar_pattern_ops, bpchar_pattern_ops はそれぞれ text, varchar, char 型に対する B-tree インデックスをサポートします)

3、最適化のアイデアは、%X列のインデックスを使用することはできません、あなたは新しい列アンチストレージ列を追加することができます、%XにX%。

4. 複雑なSQLでもできるだけインデックスを呼び出せるように、オーバーレイインデックスを作成する。

5、ビジネスロジックを調整し、LIKE文を使わないようにするか、WHERE内のLIKE文の位置を調整する。

PostgreSQLデータベースでLIKE文の効率を確保する方法についてのこの記事はここで紹介されて、もっと関連するPostgreSQLはLIKE文の内容の効率を確保してくださいBinaryDevelopの以前の記事を検索して、または次の関連記事を閲覧して続けて、あなたがBinaryDevelopをもっとサポートすることを願っています!