Оптимизация поиска MySQL с использованием "похожих" и подстановочных знаков
Как могут такие запросы, как
SELECT * FROM sometable WHERE somefield LIKE '%value%'
оптимизирован?
Основная проблема здесь - это первый шаблон, который не позволяет DBMS использовать индекс.
Изменить: более того, какое-либо значение является сплошной строкой (а не фрагментом текста), поэтому полнотекстовый поиск не может быть выполнен.
Ответы
Ответ 1
Два способа:
(1) используйте таблицу в памяти, чтобы она работала очень быстро.
(2) приготовить лучший индекс и алгоритм поиска, чем foo LIKE '%bar%'
. Невозможно сделать какие-либо предложения об этом, не зная больше о вашей проблеме.
Как вы указали, шаблон% bar% гарантирует сканирование таблицы для каждого поиска, что сводит на нет любую возможную изобретательность поиска в программном обеспечении базы данных.
Ответ 2
Как долго ваши строки?
Если они относительно короткие (например, английские слова, avg_len = 5), и у вас есть хранилище базы данных, попробуйте этот подход:
- Для каждого слова, которое вы хотите сохранить в таблице, вместо этого используйте все возможные суффиксы этого слова. Другими словами, вы продолжаете снимать первый символ, пока ничего не останется. Например, слово
value
дает:
- Сохраните каждый из этих суффиксов в базе данных.
- Теперь вы можете искать подстроки с помощью
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 *" заставляют запускать два запроса, один для поиска полей для таблицы, а затем ваш запрос с именами полей, добавленными в.