顺序扫描使用 varchar_pattern_ops 索引的列

问题描述 投票:0回答:1

我有一个用户表,它包含位置列。我使用 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个回答
6
投票

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

WHERE lower(location) like '%nepa%'

我建议使用 trigram 索引。您不需要在索引(或查询)中使用

lower()
,因为三元组索引以几乎相同的成本支持不区分大小写的
ILIKE
(或
~*
)。

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

还有:

但是我的桌子也不大。

你似乎有倒退。如果你的表不够大,Postgres 会更快地按顺序读取它,而不用担心索引。您根本不会创建任何索引。临界点取决于许多因素。 您的索引定义一开始就没有意义:

(lower(location::text) varchar_pattern_ops)

对于 
varchar

列,请使用

varchar_pattern_ops
运算符类。
但即使对于 
lower()
输入,
text
也会返回
varchar
,因此请使用
text_pattern_ops
。但正如建议的那样,您可能根本不需要这个(或任何?)索引。
如果您仍然认为需要该索引,请考虑使用 
COLLATE "C"
索引。参见:

    text_pattern_ops 和 COLLATE "C" 之间有区别吗?
© www.soinside.com 2019 - 2024. All rights reserved.