【问题标题】:Sequential scan for column indexed with varchar_pattern_ops使用 varchar_pattern_ops 索引的列的顺序扫描
【发布时间】:2018-02-18 14:39:30
【问题描述】:

我有一个表用户,它包含位置列。我已经使用 varchar_pattern_ops 索引了位置列。但是当我运行查询计划器时,它告诉我它正在执行顺序扫描。

EXPLAIN ANALAYZE
SELECT * FROM USERS
WHERE lower(location) like '%nepa%'
ORDER BY location desc;

结果如下:

Sort  (cost=12.41..12.42 rows=1 width=451) (actual time=0.084..0.087 rows=8 loops=1)
Sort Key: location
Sort Method: quicksort  Memory: 27kB
  ->  Seq Scan on users  (cost=0.00..12.40 rows=1 width=451) (actual time=0.029..0.051 rows=8 loops=1)
      Filter: (lower((location)::text) ~~ '%nepa%'::text)
 Planning time: 0.211 ms
 Execution time: 0.147 ms

我已经通过 stackoverflow 进行了搜索。发现大多数答案类似于“postgres 在大表中执行顺序扫描,以防索引扫描会变慢”。不过我的桌子也不大。

我的users 表中的索引是:

"index_users_on_lower_location_varchar_pattern_ops" btree (lower(location::text) varchar_pattern_ops)

发生了什么事?

【问题讨论】:

    标签: sql postgresql indexing database-design pattern-matching


    【解决方案1】:

    *_patter_ops indexes 适用于 前缀匹配 - LIKE 固定在开头的模式,没有前导通配符。但不适用于您的谓词:

    WHERE lower(location) like '%nepa%'
    

    我建议您改为创建一个三元组索引。而且您不需要索引(或查询)中的lower(),因为三元组索引支持不区分大小写的ILIKE(或~*),成本几乎相同。

    按照此处的说明进行操作:

    还有:

    但我的桌子也不大。

    你似乎有那个倒退。如果您的表不够足够大,Postgres 可能会更快地按顺序读取它而不用索引。您根本不会为此创建任何索引。临界点取决于许多因素。

    除此之外:您的索引定义一开始就没有意义:

    (lower(location::text) varchar_pattern_ops)
    

    对于varchar 列,请使用varchar_pattern_ops 运算符类。
    但是,如果您投射到text,请使用text_pattern_ops。由于lower() 即使对于varchar 输入也会返回text,因此请使用text_pattern_ops。除了你可能根本不需要这个(或任何?)索引,正如建议的那样。

    【讨论】:

    • 是的。非常感谢。我一定会这样做的。你让我清楚 pattern_ops 用于前缀匹配。我以前不明白这一点。另外,我将使用 varchar 作为位置字段。你是英雄。
    猜你喜欢
    • 1970-01-01
    • 2021-06-23
    • 2021-08-12
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 2022-01-15
    • 2018-04-08
    相关资源
    最近更新 更多