Оптимизация Mysql на основе объяснения

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

SELECT 
    `User`.`id`, 
    `User`.`username`, 
    `User`.`password`, 
    `User`.`role`, 
    `User`.`created`, 
    `User`.`modified`, 
    `User`.`email`, 
    `User`.`other_user_id`, 
    `User`.`first_name`, 
    `User`.`last_name`, 
    `User`.`place_id`, 
    `Resume`.`id`, 
    `Resume`.`user_id`, 
    `Resume`.`other_resume_id`, 
    `Resume`.`other_user_id`, 
    `Resume`.`file_extension`, 
    `Resume`.`created`, 
    `Resume`.`modified`, 
    `Resume`.`is_deleted`, 
    `Resume`.`has_file`, 
    `Resume`.`is_stamped`, 
    `Resume`.`is_active` 
FROM 
    `streetofwalls`.`users` AS `User` 
    LEFT JOIN `my_database`.`attempts` AS `Attempt` 
        ON (`Attempt`.`user_id` = `User`.`id` AND `Attempt`.`test_id` != 5) 
    LEFT JOIN `my_database`.`reports` AS `Resume` 
        ON (`Resume`.`user_id` = `User`.`id`) 
WHERE 
    `Attempt`.`test_id` = 8 
    AND `Attempt`.`score` > 60 
    AND `User`.`id` IN (
        SELECT 
            `User1`.`id` 
        FROM 
            `my_database`.`users` AS User1 
            LEFT JOIN `my_database`.`tags_users` AS TagUser 
                ON (`User1`.`id`= `TagUser`.`user_id`) 
            LEFT JOIN `my_database`.`tags` AS Tag 
                ON (`TagUser`.`tag_id`= `Tag`.`id`) 
        WHERE `Tag`.`id` = (8) ) 
    AND `User`.`id` NOT IN (
        SELECT 
            `User1`.`id` 
        FROM 
            `my_database`.`users` AS User1 
            LEFT JOIN `my_database`.`tags_users` AS TagUser 
                ON (`User1`.`id`= `TagUser`.`user_id`) 
            LEFT JOIN `my_database`.`tags` AS Tag 
                ON (`TagUser`.`tag_id`= `Tag`.`id`) 
        WHERE `Tag`.`id` = (3) ) 
    AND `Resume`.`has_file` = 1 
GROUP BY `User`.`id` 
ORDER BY `Attempt`.`score` DESC;

Этот запрос генерирует следующее объяснение: объяснение для приведенного выше запроса

Как видите, у меня есть несколько индексов по этому запросу. На данный момент только таблица возобновления не может быть проиндексирована. Можно ли индексировать эту таблицу в контексте этого запроса? Есть ли другой способ ускорить этот запрос, о котором я не подумал? Это непомерно медленно для своей предполагаемой функции, и у меня нет идей. Спасибо всем, кто может помочь. Пожалуйста, дайте мне знать, если потребуется какая-либо другая информация.


person usumoio    schedule 27.11.2013    source источник
comment
Откровенно говоря, это действительно запутанный запрос, и его следует исправить до того, как вы попытаетесь его оптимизировать; Я не могу легко сказать его предназначение. Некоторые запутанные вещи: а) вы делаете левые соединения, но затем вводите ограничения в предложении where, эффективно отображая их внутренними соединениями. б) Я не могу легко сказать, почему вы используете GROUP BY, поскольку не используется агрегатная функция, и, следовательно, результирующие данные являются неопределенными, что является одной из самых уродливых особенностей MySQL. Можете ли вы предоставить образцы данных и желаемый результат?   -  person D'Arcy Rittich    schedule 27.11.2013
comment
Как указывает @RedFilter, предложение WHERE эффективно устраняет необходимость в LEFT JOIN в основном запросе. Также предложение WHERE предполагает, что пользователь должен иметь тег = 8 и не должен иметь тег = 3. Этого можно добиться более эффективными средствами, чем LEFT JOIN.   -  person user2989408    schedule 27.11.2013
comment
Я бы обратил внимание на комментарий RedFilters... но с точки зрения полной оптимизации вы, скорее всего, виноваты в операторах select в вашем предложении where. MySQL выполняет предварительную выборку в предложениях where ужасно плохо, и обычно лучше всего писать их как соединение, а не в предложении where.   -  person Twelfth    schedule 27.11.2013
comment
Хорошо, я согласен с тем, что все говорят. Я собираюсь начать изучать ваши предложения.   -  person usumoio    schedule 27.11.2013
comment
Вы должны рассмотреть возможность использования EXISTS вместо IN - это определенно должно ускорить работу.   -  person Michael Kruglos    schedule 28.11.2013


Ответы (1)


попробуйте внутреннее соединение вместо подзапроса. По умолчанию запрос направляется без обработки данных, но, возможно, вам поможет следование запросу.

ВЫБЕРИТЕ User.id, User.username, User.password, User.role, User.created, User.modified, User.email, User.other_user_id, User.first_name, User.last_name, User.place_id, Resume.Resume, _ .user_id, Resume.other_resume_id, Resume.other_user_id, Resume.file_extension, Resume.created, Resume.modified, Resume.is_deleted, Resume.has_file, Resume.is_stamped, Resume.is_active

ОТ streetofwalls.users КАК User
ЛЕВОЕ СОЕДИНЕНИЕ my_database.attempts КАК Attempt ВКЛ (Attempt.user_id = User.id И Attempt.test_id != 5) ЛЕВОЕ СОЕДИНЕНИЕ my_database.reports КАК Resume ВКЛ (Resume.user_id = User.id)

, my_database.users КАК Пользователь1

LEFT JOIN my_database.tags_users AS TagUser on (User1.id= TagUser.user_id)

LEFT JOIN my_database.tags AS Тег ВКЛ (TagUser.tag_id= Tag.id)

ГДЕ User.id = User1.id И Attempt.test_id = 8 И Attempt.score > 60
И Resume.has_file = 1 И Tag.id = '8' И Tag.id != '3' ГРУППИРОВАТЬ НА User. id ЗАКАЗ Attempt.score DESC;

person kashan    schedule 28.11.2013