[英]Using index with lower function in postgresql
要创建表和索引,请使用以下代码:
CREATE TABLE IF NOT EXISTS users (
id SERIAL NOT NULL,
name VARCHAR(512) NOT NULL,
PRIMARY KEY (id));
CREATE INDEX users_name_idx ON users (lower(name::varchar(16)));
我的问题-在以下查询中是否使用users_name_idx
索引:
SELECT * FROM users WHERE LOWER(name) LIKE 'somename%'
吗? SELECT * FROM users ORDER BY name
? 您的索引无法用于任何查询,因为该表达式与查询中的表达式不同:
test=> \d users
Table "laurenz.users"
Column | Type | Nullable | Default
--------+------------------------+----------+-----------------------------------
id | integer | not null | nextval('users_id_seq'::regclass)
name | character varying(512) | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"users_name_idx" btree (lower(name::character varying(16)::text))
test=> SET enable_seqscan = off;
test=> EXPLAIN SELECT * FROM users WHERE LOWER(name) LIKE 'somename%';
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on users (cost=10000000000.00..10000000012.10 rows=1 width=520)
Filter: (lower((name)::text) ~~ 'somename%'::text)
(2 rows)
test=> EXPLAIN SELECT * FROM users ORDER BY name;
QUERY PLAN
-----------------------------------------------------------------------------------
Sort (cost=10000000016.39..10000000016.74 rows=140 width=520)
Sort Key: name
-> Seq Scan on users (cost=10000000000.00..10000000011.40 rows=140 width=520)
(3 rows)
对于要使用的索引,您将必须在查询中使用相同的表达式,包括类型转换。
除此之外,除非您的列具有排序规则C
,否则无法在LIKE
查询中使用索引。 您可以使用text_pattern_ops
运算符类。
我猜想创建这样一个索引的原因是减小索引的大小,这是值得赞扬的事情。
我会建议这样的索引:
CREATE INDEX ON users (lower(name::varchar(16)) text_pattern_ops);
然后使用以下查询:
SELECT * FROM users
WHERE lower(name) LIKE 'somename%'
AND lower(name::varchar(16)) LIKE substr('somename%', 1, 16);
如果somename
名称的长度超过15个字符,则第二个条件可能是有损的,但是它可以使用索引。 第一个条件过滤掉误报。
不幸的是,订购时没有这样的技巧。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.