SQLite: должен ли LIKE 'searchstr%' использовать индекс?

У меня есть БД с несколькими полями

word_id — INTEGER PRIMARY_KEY
word — TEXT
...

.. и ~ 150k строк.

Поскольку это словарь, я ищу слово с маской 'search_string%', используя LIKE. Он работал очень хорошо, занимая 15 мс, чтобы найти соответствующие строки. Таблица имеет индекс для поля 'word'. Недавно я изменил таблицу (некоторые поля этой таблицы, которые выходят за рамки), и что-то случилось - для выполнения запроса требуется 400 мс, поэтому я понимаю, что теперь он не использует индекс. Прямой запрос с = вместо того, чтобы показывать результат 10 мс. Кто-нибудь знает, что здесь происходит?

Ответы

Ответ 1

В этом случае нельзя безопасно использовать индекс. Наивная реализация изменила бы это:

... WHERE word LIKE 'search_string%'

в

... WHERE word >= 'search_string' AND word < 'search_strinh'

путем увеличения последнего символа строки поиска. Операторы большего и меньшего размера могут использовать индекс, где LIKE не может.

К сожалению, это не сработает в общем случае. Оператор LIKE нечувствителен к регистру, что означает, что 'a' LIKE 'A' истинно. Вышеприведенное преобразование разбило бы любую строку поиска с заглавными буквами.

Однако в некоторых случаях вы знаете, что чувствительность к регистру не имеет значения для конкретного столбца, и вышеуказанное преобразование безопасно. В этом случае у вас есть два варианта.

  • Используйте последовательность сортировки NOCASE для индекса, который охватывает это конкретное поле.
  • Измените поведение оператора LIKE по всей программе, запустив PRAGMA case_sensitive_like = ON;

Любое из этих действий позволит SQLite прозрачно выполнить вышеуказанное преобразование; вы просто продолжаете использовать LIKE, как всегда, и SQLite перепишет базовый запрос для использования индекса.

Подробнее о "Оптимизации LIKE" вы можете узнать на странице