我有一个表用户,它包含位置列。我使用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)
发生了什么事?
答案 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
。除非您可能根本不需要此(或任何?)索引,否则建议。