Jos*_*uis 3 postgresql index pattern-matching case-sensitive
在 PostgreSQL 9.4 中,具有以下架构:
CREATE TABLE people (
id INTEGER PRIMARY KEY,
name TEXT,
junk CHAR(1000)
);
INSERT INTO people(id, name)
SELECT generate_series(1,100000), md5(random()::text);
CREATE INDEX ON people (name text_pattern_ops);
Run Code Online (Sandbox Code Playgroud)
如果我按名称搜索,则使用索引:
test=# explain analyze select id, name from people where name like 'a%';
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on people (cost=248.59..1160.92 rows=6061 width=37) (actual time=2.412..8.340 rows=6271 loops=1)
Filter: (name ~~ 'a%'::text)
Heap Blocks: exact=834
-> Bitmap Index Scan on people_name_idx (cost=0.00..247.08 rows=6266 width=0) (actual time=2.123..2.123 rows=6271 loops=1)
Index Cond: ((name ~>=~ 'a'::text) AND (name ~<~ 'b'::text))
Planning time: 0.600 ms
Execution time: 8.991 ms
Run Code Online (Sandbox Code Playgroud)
但如果我替换TEXT
为CITEXT
:
CREATE EXTENSION CIText;
CREATE TABLE people (
id INTEGER PRIMARY KEY,
name CITEXT,
junk CHAR(1000)
);
Run Code Online (Sandbox Code Playgroud)
不再使用索引:
test=# explain analyze select id, name from people where name like 'a%';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
Seq Scan on people (cost=0.00..2084.00 rows=500 width=36) (actual time=5.700..152.572 rows=6305 loops=1)
Filter: (name ~~ 'a%'::citext)
Rows Removed by Filter: 93695
Planning time: 0.764 ms
Execution time: 153.046 ms
Run Code Online (Sandbox Code Playgroud)
根据CITEXT
PostgreSQL 文档,行为应该与TEXT
:
否则,它的行为几乎与文本完全一样。
如何告诉 PostgreSQL 使用索引?
索引使用text_pattern_ops
(以及使用C
语言环境时的默认运算符类)取决于字符数据的二进制表示。citext
在保留大小写的情况下存储原始值,所以一定有问题......
无论哪种方式,citext
或者text
,您都可以使其与表达式索引一起使用:
CREATE INDEX people_name_idx ON people (lower(name) text_pattern_ops);
Run Code Online (Sandbox Code Playgroud)
以及相应的查询:
SELECT id, name FROM people WHERE lower(name) LIKE 'abc%';
Run Code Online (Sandbox Code Playgroud)
请注意,即使在提供lower(name)
数据时text
,也会返回数据类型citext
。
或者,您可以使用 trigram 索引,它的维护成本更高,但也提供更多功能:
旁白:你的测试用例是次优的,因为你的虚拟值是开始与所有小写的模式'a%'
往往是不足够的选择性使用索引在所有。并且char(1000)
没有意义(即使与测试无关)。