postgresql "SELECT title FROM table WHERE title ILIKE %keyword%" 没有使用 BTREE INDEX

postgresql "SELECT title FROM table WHERE title ILIKE %keyword%" not using BTREE INDEX

首先我创建了 table 和 index ,这里是定义:

    CREATE TABLE boxes(id SERIAL PRIMARY KEY, text text, name character varying(255) COLLATE pg_catalog."C.UTF-8")

    development=# CREATE INDEX boxes_name_idx ON boxes USING btree (name COLLATE pg_catalog."C.UTF-8" varchar_pattern_ops);
    development=# \d boxes
                             Table "public.boxes"
    Column |          Type          |                     Modifiers
    --------+------------------------+----------------------------------------------------
    id     | integer                | not null default nextval('boxes_id_seq'::regclass)
    text   | text                   |
    name   | character varying(255) | collate C.UTF-8
    Indexes:
        "boxes_pkey" PRIMARY KEY, btree (id)
        "boxes_name_idx" btree (name varchar_pattern_ops)

其次,将10003项插入tables,并解释查询。但变化缓慢:

development=# EXPLAIN ANALYZE SELECT name FROM boxes  WHERE name  ILIKE '%商品%';
                                        QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on boxes  (cost=626.93..1019.21 rows=3 width=87) (actual time=2.356..48.937 rows=3 loops=1)
   Filter: ((name)::text ~~* '%商品%'::text)
   Rows Removed by Filter: 10100
   Heap Blocks: exact=266
   ->  Bitmap Index Scan on boxes_name_idx  (cost=0.00..626.92 rows=10103 width=0) (actual time=1.910..1.910 rows=10103 loops=1)
 Planning time: 0.509 ms
 Execution time: 48.973 ms
    (7 rows)



development=# EXPLAIN ANALYZE SELECT name FROM boxes  WHERE name COLLATE pg_catalog."C.UTF-8"  ILIKE '%商品%';
                                QUERY PLAN
 ---------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on boxes  (cost=626.93..1019.21 rows=3 width=87) (actual time=2.358..49.039 rows=3 loops=1)
   Filter: ((name)::text ~~* '%商品%'::text)
   Rows Removed by Filter: 10100
   Heap Blocks: exact=266
   ->  Bitmap Index Scan on boxes_name_idx  (cost=0.00..626.92 rows=10103 width=0) (actual time=1.896..1.896 rows=10103 loops=1)
 Planning time: 0.506 ms
 Execution time: 49.073 ms
(7 rows)



development=# SELECT name FROM boxes  WHERE name  ILIKE '%商品%';
    name
    -----------
 商品标题3
 商品标题
 商品标题2
 (3 rows)


development=# SELECT count(id) FROM  boxes;
    count
    -------
 10103
(1 row)


development=# SHOW LC_COLLATE;
lc_collate
-------------
en_HK.UTF-8
(1 row)

我们可以看到,索引没有被Filter使用。

我的 PostgreSQL 版本是 9.5.1

documentation在这一点上说得很清楚了:

The optimizer can also use a B-tree index for queries involving the pattern matching operators LIKE and ~ if the pattern is a constant and is anchored to the beginning of the string — for example, col LIKE 'foo%' or col ~ '^foo', but not col LIKE '%bar'.

您的模式以通配符开头。因此,它不使用索引。

Postgres 有 GIN、GIST 和 n-gram 索引来支持全文支持。