在postgresql中使用带lower函数的索引

在postgresql中使用带lower函数的索引,sql,postgresql,Sql,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\u name\u idx索引: 从较低(名称)的用户(如“so

要创建表和索引,我使用以下代码:

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\u name\u idx
索引:

  • 从较低(名称)的用户(如“somename%”中选择*
  • 按名称从用户订单中选择*

  • 索引不能用于任何查询,因为表达式与查询中的表达式不同:

    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
    ,否则您的索引不能在类似
    的查询中使用。您已经允许使用
    text\u pattern\u 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个字符,则第二个条件可能是有损的,但它可以使用索引。第一个条件过滤掉误报


    不幸的是,在订购时没有类似的技巧。

    检查执行计划,您就会知道。但是,如果只有前16个字符是重要的,那么为什么您要将
    name
    定义为512个字符?非常感谢您的帖子。这解释了很多问题。我以为我疯了。顺便说一句,最好是问一下你真正的问题,而不是你解决方案中的问题。很遗憾,我不能同意你的看法,因为问题的类型取决于男人需要什么。如果一个人需要找到一个解决方案,他是在谈论他的问题,并询问解决方案。如果一个人试图找到为什么某些技术是这样工作而不是那样工作的答案,他会问这个技术特性。我没有意识到这是一个理论问题(这很好)。这个问题看起来你有一个实际的问题。我同意减少索引大小是好的,但是当我使用ORM时,我不得不拒绝。因此,我在用户上创建索引用户\u name\u idx(较低的(名称),文本\u模式\u ops)中使用较低的(名称)如“…%”时,使用这样的索引进行编码>
    这没关系。问题是在
    按较低(名称)排序时
    按名称排序时
    不使用此索引。还是我理解错了?