2013-09-22 3 views
1

Я хотел бы сделать системный whitch позволяет искать сообщения пользователей конкретным пользователем. предположить, имеющее folowing таблицыCompound FULLTEXT index в MySQL

create table messages(
    user_id int, 
    message nvarchar(500)); 

Так, какой индекс следует использовать здесь, если я хочу, чтобы найти все сообщения от пользователя 1, содержащего слово «Foo».

  1. Simple, не уникальный индекс user_id
    Он будет фильтровать только определенные пользовательские сообщения, то без обозначения даты полного сканирования для конкретного слова.
  2. FULLTEXT индекс сообщения
    это будет найти все сообщения от всех пользователей, а затем фильтровать по идентификатору, кажется, очень неэффективен в случае большого количества пользователей.
  3. comopound индекс как user_id и сообщения
    Так полнотекстовый индекс дерева создаются для каждого пользователя в отдельности, так что они могут быть найдены в индивидуальном порядке. Во время запроса система фильтрует сообщения на ID, а затем выполняет текстовый поиск по оставшимся строкам в индексе.

A.F.A.I.K. последнее невозможно. Итак, я предполагаю, что буду использовать 1-й вариант, он будет работать лучше в случае нескольких тысяч пользователей?

И если у каждого будет ~ 100 сообщений, полная итерация не будет стоить больших ресурсов?

Возможно, я могу включить имя пользователя в сообщение и использовать режим полнотекстового поиска BOOLEAN, но я думаю, что это будет медленнее, чем с помощью индексированного user_id.

ответ

2

@ Ответ Алдена Куимби правильный, насколько это возможно, но есть еще история, потому что MySQL будет только попробует выбрать оптимальный индекс, и его способность сделать это определение ограничена из-за способа полнотекстовые индексы взаимодействуют с оптимизатором.

Что на самом деле происходит:

Если указанный user_id существует в 0 или 1 совпадающие строки в таблице, оптимизатор поймет это и будет выбрать user_id как индекс для этого запроса. Быстрое выполнение.

В противном случае оптимизатор выберет полнотекстовый индекс, который будет фильтровать каждую строку, соответствующую индексу полного текста, для исключения строк, не содержащих user_id, который соответствует предложению WHERE. Не так быстро.

Так что это не по-настоящему «оптимальный» путь. Это больше похоже на полный текст, с хорошей оптимизацией, чтобы избежать полнотекстового поиска в соответствии с одним условием, которое, как мы знаем, почти ничего не представляет интереса в таблице.

Причина, по которой это ломается, заключается в том, что индекс полного текста не дает значимой статистики обратно оптимизатору. Он просто говорит: «Да, я думаю, что для запроса, вероятно, потребуется только проверка 1 строки» ... что, конечно же, радует оптимизатор, поэтому индекс полного текста выигрывает ставку за самую низкую стоимость, если только индекс с целым числом значение также приходит сравнительно мало или ниже.

Тем не менее, это не значит, что я не пробовал бы это первым.

Есть еще один вариант, который лучше всего работал бы с полнотекстовыми запросами IN BOOLEAN MODE, и это должно создать другой столбец, который вы заполняете чем-то вроде CONCAT ('user_id _', user_id) или что-то подобное, а затем объявляете полнотекстовый текст из 2 столбцов индекс.

filter_string VARCHAR(48) # populated with CONCAT('user_id_',user_id); 
.... 
FULLTEXT KEY (message,filter_string) 

Затем укажите все в запросе.

SELECT ... 
WHERE user_id = 500 AND 
MATCH (message,filter_string) AGAINST ('+kittens +puppies +user_id_500' IN BOOLEAN MODE); 

Теперь индекс полнотекстового будет нести ответственность за соответствие только те строки, где котята, щенки, и появляется «user_id_500» в сводном индексе полнотекстового двух столбцов, но вы все еще хотите иметь целое число также фильтруйте там, чтобы убедиться, что окончательные результаты ограничены, несмотря на случайный внешний вид «user_id_500» в сообщении.

+0

Спасибо за такой полный ответ, я подумал об использовании user_id_500 для индекс. Я думаю, что я буду тестировать различные сценарии, включая очертание по ID пользователя между разными таблицами (например, 20 пользователей в таблице, чтобы сделать полный текстовый индекс эффективным) и выполнять тесты. –

1

Вы должны добавить полнотекстовый индекс на message и регулярный индекс по user_id и использовать запрос:

SELECT * 
FROM messages 
WHERE MATCH(message) AGAINST(@search_query) 
AND user_id = @user_id; 

Вы правы, что вы не можете сделать вариант 3. Но вместо того, чтобы выбрать от 1 до 2, пусть MySQL сделает для вас работу. MySQL будет использовать только один из двух индексов и будет выполнять линейное сканирование для завершения второго фильтра, но он будет оценивать эффективность каждого индекса и выбирать оптимальный.

Примечание: сделайте это только в том случае, если вы можете позволить себе накладные расходы на два индекса (более медленная вставка/обновление/удаление). Кроме того, если вы знаете, у каждого пользователя будет только несколько сообщений, тогда да, возможно, имеет смысл использовать простой индекс и делать регулярное выражение на прикладном уровне или что-то в этом роде.

+0

Я думаю, я попробую разные сценарии, чтобы проверить, что работает лучше, к сожалению, мы не можем комбинировать ** обычный ** индекс с ** полным текстом ** –