简体   繁体   English

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

[英]Using index with lower function in postgresql

To create my table and index I use the following code: 要创建表和索引,请使用以下代码:

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)));

My question - is users_name_idx index used in the following queries: 我的问题-在以下查询中是否使用users_name_idx索引:

  1. SELECT * FROM users WHERE LOWER(name) LIKE 'somename%' ? SELECT * FROM users WHERE LOWER(name) LIKE 'somename%'吗?
  2. SELECT * FROM users ORDER BY name ? SELECT * FROM users ORDER BY name

Your index can be used by none of your queries, because the expression is not the same as in the queries: 您的索引无法用于任何查询,因为该表达式与查询中的表达式不同:

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)

For the index to be used, you would have to use the same expression, including the type cast, in your queries. 对于要使用的索引,您将必须在查询中使用相同的表达式,包括类型转换。

In addition to that, unless your column has collation C , your index cannot be userd in LIKE queries. 除此之外,除非您的列具有排序规则C ,否则无法在LIKE查询中使用索引。 You'd gave to use the text_pattern_ops operator class. 您可以使用text_pattern_ops运算符类。

I guess that the reason behind creating such an index is to reduce the size of the index, which is a commendable thing to do. 我猜想创建这样一个索引的原因是减小索引的大小,这是值得赞扬的事情。

I would recommend an index like this: 我会建议这样的索引:

CREATE INDEX ON users (lower(name::varchar(16)) text_pattern_ops);

Then use this query: 然后使用以下查询:

SELECT * FROM users
WHERE lower(name) LIKE 'somename%'
  AND lower(name::varchar(16)) LIKE substr('somename%', 1, 16);

The second condition could be lossy if somename is longer than 15 characters, but it can use the index. 如果somename名称的长度超过15个字符,则第二个条件可能是有损的,但是它可以使用索引。 The first condition filters out the false positives. 第一个条件过滤掉误报。

Unfortunately, there is no trick like this when it comes to ordering. 不幸的是,订购时没有这样的技巧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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