【问题标题】:Postgres LIKE '...%' doesn't use indexPostgres LIKE '...%' 不使用索引
【发布时间】:2020-04-25 08:04:28
【问题描述】:

我有一个表,我想在其中按主键的前缀进行搜索。主键具有03.000221.103.000221.203.000221.3 等值,我想检索所有以03.000221. 开头的值。

我的第一个想法是使用 LIKE '03.000221.%' 进行过滤,认为 Postgres 足够聪明,可以在索引中查找 03.000221. 并从该点执行范围扫描。但是不,这会执行顺序扫描。

                                                   QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..253626.34 rows=78 width=669)
   Workers Planned: 2
   ->  Parallel Seq Scan on ...  (cost=0.00..252618.54 rows=32 width=669)
         Filter: ((id ~~ '03.000221.%'::text)
 JIT:
   Functions: 2
   Options: Inlining false, Optimization false, Expressions true, Deforming true

如果我使用普通的 >=< 范围进行等效操作,例如。 G。 id >= '03.000221.' and id < '03.000221.Z' 它确实使用了索引:

                                                                 QUERY PLAN                                                                  
---------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using ... on ...  (cost=0.56..8.58 rows=1 width=669)
   Index Cond: ((id >= '03.000221.'::text) AND (id < '03.000221.Z'::text))

但这更脏,在我看来,Postgres 应该能够推断出它可以使用LIKE 进行等效的索引范围查找。为什么不呢?

【问题讨论】:

    标签: postgresql indexing


    【解决方案1】:

    如果您使用 text_pattern_ops 运算符构建索引,或者您使用 C 排序规则,PostgreSQL 将执行此操作。

    如果您使用一些随机的其他排序规则,PostgreSQL 就无法推断出太多关于它的任何东西。在非常常见的“en_US.utf8”排序规则中观察这一点。

    select * from (values ('03.000221.1'), ('03.0002212'), ('03.000221.3')) f(x) order by x;
          x      
    -------------
     03.000221.1
     03.0002212
     03.000221.3
    

    这自然会导致您的查询出现错误答案:

    select * from (values ('03.000221.1'), ('03.0002212'), ('03.000221.3')) f(id)
        where ((id >= '03.000221.'::text) AND (id < '03.000221.Z'::text))
         id      
    -------------
     03.000221.1
     03.0002212
     03.000221.3
    

    【讨论】:

    • 对于给定的值,collate "C" 可能是最好的选择
    • 我使用的是 C.UTF-8,这显然还不够 C。谢谢!
    • @ToniCárdenas 我从来不理解 C 和 C.UTF-8 之间的区别。我认为也许 C 是作为一种特殊情况在内部实现的,而 C.UTF-8 是外包给 glibc 的。它可能可以通过 C.UTF-8 使用索引并获得正确答案,只是它不知道它可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    相关资源
    最近更新 更多