繁体   English   中英

在PostgreSQL中使用具有较低功能的索引

[英]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索引:

  1. SELECT * FROM users WHERE LOWER(name) LIKE 'somename%'吗?
  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM