Оптимизация поиска MySQL с использованием "похожих" и подстановочных знаков

Как могут такие запросы, как

SELECT * FROM sometable WHERE somefield LIKE '%value%'

оптимизирован?

Основная проблема здесь - это первый шаблон, который не позволяет DBMS использовать индекс.

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

Ответы

Ответ 1

Два способа:

(1) используйте таблицу в памяти, чтобы она работала очень быстро.

(2) приготовить лучший индекс и алгоритм поиска, чем foo LIKE '%bar%'. Невозможно сделать какие-либо предложения об этом, не зная больше о вашей проблеме.

Как вы указали, шаблон% bar% гарантирует сканирование таблицы для каждого поиска, что сводит на нет любую возможную изобретательность поиска в программном обеспечении базы данных.

Ответ 2

Как долго ваши строки?

Если они относительно короткие (например, английские слова, avg_len = 5), и у вас есть хранилище базы данных, попробуйте этот подход:

  • Для каждого слова, которое вы хотите сохранить в таблице, вместо этого используйте все возможные суффиксы этого слова. Другими словами, вы продолжаете снимать первый символ, пока ничего не останется. Например, слово value дает:
    • value
    • alue
    • lue
    • ue
    • e
  • Сохраните каждый из этих суффиксов в базе данных.
  • Теперь вы можете искать подстроки с помощью LIKE 'alu%' (который найдет "alu" как часть "значения" ).

Сохраняя все суффиксы, вы удалили необходимость в главном шаблоне (позволяя индексу использовать для быстрого поиска) за счет места хранения.

Стоимость хранения

Количество символов, необходимых для хранения слова, становится word_len*word_len / 2, т.е. квадратичным по длине слова, для каждого слова. Вот фактор увеличения для разных размеров слов:

  • 3-буквенное слово: (3*3/2) / 3 = 1.5
  • 5-буквенное слово: (5*5/2) / 5 = 2.5
  • 7-буквенное слово: (7*7/2) / 7 = 3.5
  • 12-буквенное слово: (12*12/2) / 12 = 6

Количество строк, необходимых для хранения слова, увеличивается от 1 до word_len. Помните об этом накладных расходов. Дополнительные столбцы должны быть сведены к минимуму, чтобы избежать хранения больших объемов избыточных данных. Например, номер страницы, на котором было изначально обнаружено слово, должен быть точным (думаю, unsigned smallint), но обширные метаданные для этого слова должны храниться в отдельной таблице на основе каждого слова, а не для каждого суффикса.

Вопросы

Существует компромисс, в котором мы разделяем слова (или фрагменты). Как реальный пример: что мы делаем с дефисом? Сохраняем ли мы прилагательное five-letter как одно слово или два?

Компромисс выглядит следующим образом:

  • Все, что разбито, не может быть найдено как один элемент. Если мы сохраним five и letter отдельно, поиск five-letter или fiveletter завершится с ошибкой.
  • Все, что не сломано, займет больше места для хранения. Помните, что хранилище требование увеличивается квадратично в длину слова.

Для удобства вы можете удалить дефис и сохранить fiveletter. Теперь слово можно найти, выполнив поиск five, letter и fiveletter. (Если вы разделите дефисы с любым поисковым запросом, пользователи все равно смогут найти five-letter.)

Наконец, существуют способы хранения массивов суффиксов, которые не требуют больших накладных расходов, но я еще не уверен, хорошо ли они хорошо переносятся в базы данных.

Ответ 3

Используйте Полнотекстовый поиск. Заголовок "Начальная идея" имеет тот же пример и приводит к отработанному примеру решения.

И документы docs

Изменить: он не может быть настроен в самом SQL. Использование таких функций, как LOCATE или PATINEX, тоже не поможет.

Ответ 4

Это не будет иметь большого значения, учитывая, что ваша проблема связана с шаблоном, но не с помощью "SELECT *" улучшит производительность запросов. Если вы фактически не используете все поля, которые вы возвращаете, то выигрыш и "SELECT *" заставляют запускать два запроса, один для поиска полей для таблицы, а затем ваш запрос с именами полей, добавленными в.