使用varchar_pattern_ops索引的列的顺序扫描

时间:2017-09-10 04:33:31

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

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

发生了什么事?

1 个答案:

答案 0 :(得分:2)

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

WHERE lower(location) like '%nepa%'

我建议您改为创建三元组索引。并且您在索引(或查询)中不需要lower(),因为trigram索引支持不区分大小写的ILIKE(或~*),实际上成本相同。

按照此处的说明操作:

此外:

  

但我的桌子也不大。

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

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

(lower(location::text) varchar_pattern_ops)

对于varchar列,请使用varchar_pattern_ops运算符类 但如果您转向text,请使用text_pattern_ops。由于lower()即使text输入也会返回varchar,因此请使用text_pattern_ops。除非您可能根本不需要此(或任何?)索引,否则建议。