Postgres相似度函数未正确使用Trigram索引

时间:2018-11-13 16:32:12

标签: postgresql similarity postgresql-10 trigram

我有一个带有person列的简单last_name表,并在其中添加了GIST索引

CREATE INDEX last_name_idx ON person USING gist (last_name gist_trgm_ops);

根据https://www.postgresql.org/docs/10/pgtrgm.html上的文档,<->运算符应使用此索引。但是,当我实际上尝试通过以下查询使用此差异运算符时:

explain verbose select * from person where last_name <-> 'foobar' > 0.5;

我回来了:

Seq Scan on public.person  (cost=0.00..290.82 rows=4485 width=233)
  Output: person_id, first_name, last_name
  Filter: ((person.last_name <-> 'foobar'::text) < '0.5'::double precision)

而且看起来好像没有使用索引。但是,如果我在此命令中使用%运算符:

explain verbose select * from person where last_name % 'foobar';

似乎使用了索引:

Bitmap Heap Scan on public.person  (cost=4.25..41.51 rows=13 width=233)
  Output: person_id, first_name, last_name
  Recheck Cond: (person.last_name % 'foobar'::text)
  ->  Bitmap Index Scan on last_name_idx  (cost=0.00..4.25 rows=13 width=0)
        Index Cond: (person.last_name % 'foobar'::text)

我还注意到,如果我将运算符移到查询的选择部分,索引将再次被忽略:

explain verbose select last_name % 'foobar' from person;

Seq Scan on public.person  (cost=0.00..257.19 rows=13455 width=1)
  Output: (last_name % 'foobar'::text)

我是否缺少关于相似性函数如何使用Trigram索引的明显信息?

我正在OSX上使用Postgres 10.5。

编辑1

根据Laurenz的建议,我尝试设置enable_seqscan = off,但不幸的是,使用<->运算符的查询似乎仍然忽略了索引。

show enable_seqscan;
 enable_seqscan
----------------
 off

explain verbose select * from person where last_name <-> 'foobar' < 0.5;

-----------------------------------------------------------------------------------------------------------------------------
 Seq Scan on public.person  (cost=10000000000.00..10000000290.83 rows=4485 width=233)
   Output: person_id, first_name, last_name
   Filter: ((person.last_name <-> 'foobar'::text) < '0.5'::double precision)

1 个答案:

答案 0 :(得分:1)

对于所有类型的索引,这种行为都是正常的。

第一个查询的格式不能使用索引。为此,条件必须为以下形式

<indexed expression> <operator supported by the index> <quasi-constant>

,其中最后一个表达式在索引扫描期间保持不变,并且运算符返回布尔值。您的表达式“ last_name <->'foobar'> 0.5`”不是这种形式。

必须在<->子句中使用ORDER BY运算符才能使用索引。

第三个查询不使用索引,因为该查询会影响表的 all 行。索引不会加快对表达式的求值速度,它仅对快速标识表的子集(或以特定的排序顺序获取行)有用。