Ответ 1
IMMUTABLE вариант unaccent()
Чтобы прояснить дезинформацию в в настоящее время принятом неверном ответе:
Индексы выражений допускают только функции IMMUTABLE
(по понятным причинам), а unaccent()
- только STABLE
. Решение предложенное вами в комментарии, также проблематично. Подробное объяснение и правильное решение для этого:
В зависимости от содержимого tags->name
может быть полезно добавить unaccent()
в индекс выражения, но это ортогонально вопросу о том, почему индекс не использовался:
Актуальная проблема/решение
Оператор LIKE
в вашем запросе тонко неправильный (скорее всего). Вы не хотите интерпретировать "Weststrasse" как шаблон поиска, вы хотите совместить (нормированную) строку как есть. Замените его оператором =
, и вы увидите сканирование индекса (bitmap) с вашим текущим индексом, независимо от волатильности функции unaccent()
:
SELECT * FROM germany.ways
WHERE lower(tags->'name') = lower(unaccent('unaccent','Weststrasse'))
Почему?
Правым операндом LIKE
является шаблон. Postgres не может использовать простой индекс btree для соответствия шаблону (исключения применяются). A LIKE
с простой строкой в виде шаблона (без специальных символов) можно оптимизировать с помощью проверки равенства на индексе btree. Но если в строке есть специальные символы, этот индекс отсутствует.
Если есть функция IMMUTABLE
справа от LIKE
, ее можно сразу оценить, и указанная оптимизация по-прежнему возможна. Per документация по Категории волатильности функций:
IMMUTABLE
...
Эта категория позволяет оптимизатору предварительно оценить функцию, когда запрос вызывает его с постоянными аргументами.
То же самое невозможно при меньшей волатильности функции (STABLE
или VOLATILE
). Вот почему ваше "решение" фальсификации IMMUTABLE unaccent()
, похоже, сработало, но оно действительно накладывает помаду на свинью.
Повторить:
- Если вы хотите работать с
LIKE
и шаблонами, используйте индекс триграммы. - Если вы не хотите работать с
LIKE
и шаблонами, используйте оператор равенства=