Достаточно ли быстрой этой стратегии для быстрого поиска подстроки в MySQL? - PullRequest
2 голосов
/ 20 июня 2020

У меня есть таблица USER с миллионами строк. Я реализую функцию поиска, которая позволяет кому-то искать пользователя, вводя имя пользователя. Эта функция автозаполнения должна быть невероятно быстрой. Учитывая, что в MySQL индексы столбцов ускоряют запросы с использованием LIKE {string}%, достаточно ли эффективен следующий подход для возврата в течение 200 мс? (Примечание: накладные расходы на память здесь не проблема, имя пользователя не более 30 символов.)

    USERSEARCH
    
    user_id    username_ngram   
    -------------------------
    1          crazyguy23         
    1          razyguy23       
    1          azyguy23      
    1          zyguy23       
    ...       

Тогда запрос будет:

    SELECT user_id FROM myapp.usersearch WHERE username_ngram LIKE {string}%
    LIMIT 10

Я знаю, что существуют сторонние решения, но я хотел бы держаться от них подальше по другим причинам. Жизнеспособен ли этот подход с точки зрения скорости? Не переоцениваю ли я мощь индексов, если БД потребуется проверить все O (30n) строк, где n - количество пользователей?

Ответы [ 3 ]

1 голос
/ 20 июня 2020

Наверное, нет. union distinct будет обрабатывать каждый подзапрос до завершения.

Если вам нужны просто произвольные строки, сформулируйте это как:

(SELECT user_id
 FROM myapp.usersearch
 WHERE username_1 LIKE {string}%
 LIMIT 10
) UNION DISTINCT
(SELECT user_id
 FROM myapp.usersearch
 WHERE username_2 LIKE {string}%
 LIMIT 10
)
LIMIT 10;

Это, по крайней мере, сэкономит вам много времени для общих префиксы - скажем, 'S'.

Тем не менее, это просто возвращает произвольный список из 10 user_id s, хотя их может быть намного больше.

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

0 голосов
/ 22 июня 2020

Предполагая SSD, это должно быть быстро, да.

Вот еще несколько оптимизаций:

  1. Я бы добавил DISTINCT к вашему запросу, поскольку нет смысла возвращать один и тот же user_id несколько раз. Особенно при поиске очень распространенного префикса, такого как отдельная буква.

  2. Также рассмотрите возможность поиска не менее 3 букв ввода. Меньше имеет тенденцию быть бессмысленным (поскольку, надеюсь, ваши имена пользователей состоят как минимум из 3 символов) и ненужным ударом по вашей базе данных.

  3. Если вы не добавляете больше столбцов (я надеюсь, это не так, поскольку эта таблица предназначена для невероятно быстрого поиска!), мы можем сделать лучше. Поменяйте местами столбцы. Сделайте первичный ключ (username_ngram, user_id). Таким образом, вы выполняете поиск непосредственно по первичному ключу. (Обратите внимание на дополнительное преимущество алфавитного упорядочения результатов! Ну ... алфавит c на совпадающих суффиксах, то есть не полные имена пользователей.)

  4. Убедитесь, что вы иметь индекс для user_id, чтобы иметь возможность заменить все для пользователя, если вам когда-либо понадобится изменить имя пользователя. (Для этого просто удалите все строки для этого user_id и вставьте новые.)

  5. Возможно, мы сможем сделать еще лучше. Поскольку это только для быстрого поиска, вы можете использовать уровень изоляции READ_UNCOMMITTED. Это позволяет избежать блокировок чтения, если я не ошибаюсь, и должно быть еще быстрее. Он может читать незафиксированные данные, ну и что ... После этого вы просто запросите любые результирующие user_ids в другой таблице и, возможно, не найдете их, если этот пользователь все еще создавался. Вы ничего не потеряли. :)

0 голосов
/ 21 июня 2020

Думаю, вам нужно использовать mysql полнотекстовый индекс для повышения производительности. Для использования полнотекстового индекса необходимо изменить синтаксис.

Создать полнотекстовый индекс :

CREATE FULLTEXT INDEX ix_usersearch_username_ngram ON usersearch(username_ngram);

Официальный mysql документация по использованию полнотекстового индекса : https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...