Функция сходства Postgres неправильно использует индекс триграммы

У меня есть простая таблица 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)

Я также заметил, что если я перемещаю оператор в часть запроса select, индекс снова игнорируется:

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)

Я упускаю что-то очевидное в том, как функция подобия использует индекс триграммы?

Я использую Postgres 10.5 на OSX.

РЕДАКТИРОВАТЬ 1

По предложению Лоренца я попытался установить 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)

person archeezee    schedule 13.11.2018    source источник


Ответы (1)


Такое поведение является нормальным для всех типов индексов.

Первый запрос не в форме, которая может использовать индекс. Для этого условие должно иметь вид

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

где последние выражения остаются постоянными на протяжении всего сканирования индекса, а оператор возвращает логическое значение. Ваше выражение 'last_name ‹-> 'foobar' > 0.5` не имеет такой формы.

Оператор <-> должен использоваться в предложении ORDER BY, чтобы можно было использовать индекс.

Третий запрос не использует индекс, так как запрос затрагивает все строки таблицы. Индекс не ускоряет вычисление выражения, он полезен только для быстрой идентификации подмножества таблицы (или для получения строк в определенном порядке сортировки).

person Laurenz Albe    schedule 13.11.2018
comment
Спасибо, это все имеет смысл. Однако я только что попытался установить enable_seqscan = off, но запрос все еще выполняет последовательное сканирование с оператором <->. - person archeezee; 14.11.2018
comment
Я обновил вопрос результатами вашего предложения. - person archeezee; 14.11.2018