2017-02-07 3 views
0

У меня есть два MySQL запросов, которые выполняются очень быстро, но когда я их совмещаю, новый запрос выполняется очень медленно.MySQL медленный запрос при объединении двух очень быстрых запросов

Fast (< 1 секунда, 15 Результаты):

SELECT DISTINCT 
Id, Name, Company_Id 
FROM people 
where Company_Id in (5295, 1834) 
and match(Locations) against('austin') 

Быстрая (< 1 секунда, 2970 результаты):

select distinct Company_Id from technologies 
    where match(Name) against('elastic') 
     and Company_Id is not null 

Когда я объединить эти два так:

SELECT DISTINCT Id, Name, Company_Id 
FROM people 
where Company_Id in 
    (select Company_Id from technologies 
     where match(Name) against('elastic') 
      and Company_Id is not null 
    ) 
    and match(Locations) against('austin') 

Запрос на результат занимает более 2 минут. У него 278 строк.

Я пробовал переписать медленный запрос несколькими способами. Другой пример такой:

SELECT DISTINCT 
`Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Company_Id` 
FROM `people` AS `Extent1` 
INNER JOIN `technologies` AS `Extent2` 
    ON (`Extent1`.`Company_Id` = `Extent2`.`Company_Id`) 
WHERE (`Extent1`.`Company_Id` IS NOT NULL) 
AND ((match(`Extent1`.`Locations`) against('austin')) 
AND (match(`Extent2`.`Name`) against('elastic'))) 

Я использую MySQL 5.7 для Windows. У меня есть полный текстовый индекс в столбцах Name и Location. Мое использование буфера InnoDB никогда не превышает 40%. Я попытался использовать рабочий стол MySQL, чтобы посмотреть план выполнения, но он показывает «Объяснить данные, недоступные для справки»

Пожалуйста, дайте мне знать, если вы увидите что-нибудь, что я мог бы улучшить или попробовать. Спасибо.

+0

Я думаю, что последнее предложение ответа Гордона - это вопрос, который стоит рассмотреть. – Strawberry

+0

Да, но местоположения - это не список. Это простой столбец longtext (Entity Framework sourced) с индексом Full Text на нем. У меня такая же проблема с другими столбцами Person (Name и т. Д.), Которые похожи на longtext с индексом FT. – Erik

+0

Мне было бы интересно увидеть вывод 'EXPLAIN' в этом запросе, чтобы узнать, какие таблицы сканируются и где стоимость поиска самая дорогая. – Nathan

ответ

3

IN (SELECT ...) плохо оптимизирован, по крайней мере, в более старых версиях MySQL. Какую версию ты используешь?

При использовании индекса FULLTEXT (MATCH...) эта часть выполняется, если это возможно, в первую очередь. Это связано с тем, что почти всегда поиск FT быстрее, чем что бы то ни было.

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

Вот один возможный обходной путь:

  • Иметь дополнительную таблицу для поиска. Он включает в себя как Name, так и Locations.
  • У FULLTEXT(Name, Locations)
  • MATCH (Name, Locations) AGAINST ('+austin +elastic' IN BOOLEAN MODE)

В случае необходимости AND, что с чем-то, чтобы убедиться, что это не так, например, найти человека по имени «Остин».

Другая возможность:

5,7 (или 5,6?) может быть в состоянии оптимизировать это путем создания индексов подзапросов:

SELECT ... 
    FROM (SELECT Company_Id FROM ... MATCH(Name) ...) AS x 
    JOIN (SELECT Company_Id FROM ... MATCH(Locations) ...) AS y 
     USING(Company_id); 

Обеспечить EXPLAIN; Я надеюсь увидеть <auto-key>.

Проверьте это. Если это «быстро», вам может потребоваться добавить еще JOIN и/или WHERE. (Я не понимаю, каков ваш окончательный запрос.)

+0

выберите * from (выберите Company_Id от людей, где матч (места) против ('austin')), как x Присоединиться (выберите Company_Id из технологий, где совпадение (имя) против («эластичный»)), как y ИСПОЛЬЗОВАНИЕ (Company_id) ; – Erik

+0

Это отлично работало. Должно быть, это были «две полнотекстовые запросы». Я объяснил, и он показывает, что он использует таблицу производных . Удивительно, но старый «медленный» запрос выполняется быстро. Объясните, что старый «медленный» запрос использует таблицу . Спасибо. – Erik

2

Написать запрос с подзапроса в предложении from:

select distinct p.Id, p.Name, p.Company_Id 
from people p join 
    (select Company_Id 
     from technologies 
     where match(Name) against('elastic') and Company_Id is not null 
    ) t 
    on p.Company_Id = t.Company_Id 
where match(p.Locations) against ('austin'); 

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

+0

Хорошее предложение, и этот запрос дает мне правильные результаты - но мне все равно потребовалось 110 секунд. – Erik

Смежные вопросы