Почему LIKE более чем в 4 раза быстрее, чем MATCH… ПРОТИВ индекса FULLTEXT в MySQL?


12

Я не понимаю этого.

У меня есть таблица с этими индексами

PRIMARY     post_id
INDEX       topic_id
FULLTEXT    post_text

Таблица имеет (только) 346 000 строк. Я пытаюсь выполнить 2 запроса.

SELECT post_id 
FROM phpbb_posts 
WHERE topic_id = 144017 
AND post_id != 155352 
AND MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar')

занимает 4,05 секунды

SELECT post_id 
FROM phpbb_posts 
WHERE topic_id=144017 
AND post_id != 155352 
AND post_text LIKE ('%http://rapidshare.com/files/5494794/photo.rar%')

занимает 0,027 секунды.

EXPLAIN показывает, что единственная разница заключается в возможном fulltextключе (включая post_text, LIKEнет)

Это действительно странно.

Что за этим стоит? Что происходит на заднем плане? Как может LIKEбыть так быстро, когда не используется индекс, а FULLTEXT так медленно, когда используется его индекс?

Update1:

На самом деле теперь это занимает около 0,5 секунд, может быть, таблица была заблокирована, но, тем не менее, когда я включаю профилирование, это показывает, что ИНИЦИАЛИЗАЦИЯ FULLTEXT заняла 0,2 секунды. Что происходит?

Я могу запросить мою таблицу с LIKE10x в секунду, с полным текстом только 2x

UPDATE2:

Сюрприз!

mysql> SELECT post_id FROM phpbb_posts WHERE post_id != 2 AND topic_id = 6 AND MATCH(post_text) AGAINST ('rapidshare.com');
Empty set (0.04 sec)

поэтому я спрашиваю, как это возможно?

Дополнительно,

SELECT count(*) FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com')

действительно медленно. Может быть полный текст какой-нибудь сломан?

Update3:

Что за черт?

SELECT forum_id, post_id, topic_id, post_text  FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

занимает 0,27 с в то время как

SELECT count(*) FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

занимает больше 30 секунд! Что здесь не так?


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

Тестируйте запросы только с SQL_NO_CACHE .
mgutt

Это довольно старый вопрос / ответ. Какие-нибудь достижения от mysql / mariadb с тех дней?
Роман Суси

1
Предостережение: время проведения этого Q & A подразумевает, что речь идет только о MyISAM. Его применимость к InnoDB под вопросом.
Рик Джеймс

@RomanSusi - Хотите начать новый вопрос, нацеленный на InnoDB?
Рик Джеймс

Ответы:


2

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

Каждый раз, когда есть запрос, включающий индекс FULLTEXT, MySQL Query Optimizer стремится превратить запрос в полное сканирование таблицы. Я видел это на протяжении многих лет. Я также написал более раннюю статью об этом самом незначительном поведении в индексах FULLTEXT .

Вам может потребоваться сделать две вещи:

  1. рефакторинг запроса, чтобы индекс FULLTEXT не приводил оптимизатор запросов MySQL в состояние путаницы
  2. Добавьте дополнительный индекс, который будет правильно поддерживать рефакторинг запроса

РЕФАКТОР ЗАПРОСА

Вот ваш оригинальный запрос

SELECT post_id  
FROM phpbb_posts  
WHERE topic_id = 144017  
AND post_id != 155352  
AND MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar') 

Вам нужно будет реорганизовать запрос следующим образом:

SELECT subqueryA.post_id
FROM
(
    SELECT post_id FROM phpbb_posts
    WHERE topic_id = 144017
    AND post_id != 155352
) subqueryA
INNER JOIN
(
    SELECT post_id FROM phpbb_posts
    WHERE MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar')
) subqueryB
USING (post_id);

СОЗДАТЬ НОВЫЙ ИНДЕКС

Вам понадобится индекс для поддержки subqueryA. У вас уже есть индекс topic_id. Вам необходимо заменить его следующим образом:

ALTER TABLE phpbb_posts ADD INDEX topic_post_ndx (topic_id,post_id);
ALTER TABLE phpbb_posts DROP INDEX topic_id;

Попробуйте!

ОБНОВЛЕНИЕ 2012-03-19 13:08 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Попробуйте это первым

SELECT post_id FROM
(
    SELECT * FROM phpbb_posts
    WHERE topic_id = 144017
    AND post_id != 155352
) A;

Если это выполняется быстро и возвращает небольшое количество строк, попробуйте этот вложенный подзапрос:

SELECT post_id FROM
(
    SELECT * FROM phpbb_posts
    WHERE topic_id = 144017
    AND post_id != 155352
) A
WHERE MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar');

ОБНОВЛЕНИЕ 2012-03-19 13:11 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Сравните время выполнения этого:

SELECT count(*) FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

с этим

SELECT count(*) FROM phpbb_posts WHERE 1 = 1;

Если время выполнения одинаково, то предложение MATCH выполняется в каждой строке. Как я уже упоминал ранее, использование индексов FULLTEXT приводит к аннулированию любых преимуществ, предпринятых и вносимых оптимизатором запросов MySQL.


Итак, вы хотите сказать, что мой запрос на самом деле сканирует всю таблицу, потому что topic_id и post_idсмущает его? Почему запрос LIKE работает даже без индекса для этих столбцов (topic_id, post_id)? Почему MYSQL не просто интеллектуально выбирает, topic_id = 144017 AND post_id != 155352а затем просто просматривает эти результаты? А что, если в 100 тыс. Строк есть моя строка полнотекстового поиска post_text? Разве это не выберет их всех?
Бытие

На самом деле я запутался еще больше. LIKE '% text%' также не использует индексы, это означает, что он сканирует всю таблицу, так почему же это так быстро?
Бытие

Пожалуйста, посмотрите на мое ОБНОВЛЕНИЕ , я думаю, что вы решите это очень быстро. Я собираюсь дать вам мой представитель, если вы решите это.
Бытие

Отвечая на ваше второе обновление. Второй запрос выполнялся менее чем за 0,01 мс, первый не завершился. Почему вы сказали: «Если время выполнения одинаково, то предложение MATCH выполняется в каждой строке». ? Разве это не совсем противоположно тому, что должно быть? Если вы посмотрите сюда , вы увидите, что я не единственная с этой проблемой
Бытие

Отвечая на ваше первое обновление. Первый запрос выполнялся за 0,01 мс, 0 строк, второй - «Не удалось найти индекс FULLTEXT, соответствующий списку столбцов». Тем не менее, ваш запрос с 2 подзапросами работает отлично!
Бытие
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.