要创建我的表和索引,我使用以下代码:
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
?答案 0 :(得分:2)
您的索引可以不被任何查询使用,因为表达式与查询中的表达式不同:
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个字符,第二个条件可能会有损,但它可以使用索引。第一个条件过滤掉误报。
不幸的是,在订购时没有这样的技巧。