Проблема производительности с запросом mysql

Я работаю в MYSQL впервые, и у меня возникают проблемы со следующим запросом

SELECT
    t.id,
    t.name,
    t.description,
    
    (
        SELECT
            GROUP_CONCAT( CONCAT( hs.name, '|', s.rate ) )
        FROM
            occupation_skill_rate s 
            INNER JOIN hard_skills hs ON s.hard_skill_id = hs.id
        WHERE
            s.occupation_id = t.id
        ORDER BY
            s.rate DESC LIMIT 15
    ) AS skills,

    (
        SELECT
            GROUP_CONCAT( CONCAT( hs.name, '|', s.rate ) )
        FROM
            occupation_knowledge_rate s 
            INNER JOIN knowledge hs ON s.knowledge_id = hs.id
        WHERE
            s.occupation_id = t.id
        ORDER BY
            s.rate DESC LIMIT 15
    ) AS knowledge,

    (
        SELECT
            GROUP_CONCAT( CONCAT( hs.name, '|', s.rate ) )
        FROM
            occupation_abilities_rate s 
            INNER JOIN ability hs ON s.ability_id = hs.id
        WHERE
            s.occupation_id = t.id
        ORDER BY
            s.rate DESC LIMIT 15
    ) AS knowledge

FROM
    occupations t

Таблица профессий содержит 1033 строки, а в оккупации_skill_rate содержится 34 160 строк, и выполнение этого запроса занимает более 1 минуты. Пожалуйста, дайте мне знать, если вам нужны дополнительные разъяснения, чтобы помочь мне.

Спасибо за вашу помощь Аджаи

Опубликуйте EXPLAIN

Dai 08.10.2022 08:27

Видите эти уродливые красные коробки с надписью «Полное сканирование таблицы»? Вот почему ваш запрос медленный. Какие INDEX объекты вы определили в этих таблицах? Пожалуйста, покажите полный вывод EXPLAIN, так как он покажет вам, какие индексы вам нужно создать.

Dai 08.10.2022 10:44

Да, вы правы, я добавил индекс для столбца occcupation_id, и теперь полный запрос выполняется за 1 с примерно 0,600 с.

Ajai rajan 08.10.2022 11:40
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
3
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Таблицы occupation_%_rate кажутся многими ко многим, верно? Им нужны эти индексы, а не идентификатор:

PRIMARY KEY(occupation_id, xxx_id)
INDEX(xxx_id, occupation_id)

Но это похоже на ORDER BY и LIMIT при использовании с GROUP_CONCAT(). Пожалуйста, опишите цель запроса; мы можем помочь переписать его.

GROUP_CONCAT допускает пункт ORDER BY, но не LIMIT. Можно ли обойтись без LIMITs?

Пример

Вместо того

    ( SELECT  GROUP_CONCAT( CONCAT( hs.name, '|', s.rate ) )
            FROM  occupation_skill_rate s
            INNER JOIN  hard_skills hs  ON s.hard_skill_id = hs.id
            WHERE  s.occupation_id = t.id
            ORDER BY  s.rate DESC
            LIMIT  15 
    ) AS skills;

Делать

    ( SELECT  CONCAT( name, '|', rate ORDER BY  rate DESC )
            FROM (
                SELECT  hs.name, s.rate
                    FROM  occupation_skill_rate s
                    INNER JOIN  hard_skills hs
                          ON s.hard_skill_id = hs.id
                         AND s.occupation_id = t.id
                    ORDER BY  s.rate DESC
                    LIMIT  15
                 ) AS a 
    ) AS skills 

Но я подозреваю, что t не видно, что глубоко вложено.

Если это так, переставьте вещи следующим образом:

SELECT  t.id, t.name, t.description, s3.skills, ...
    FROM  occupations AS t
    JOIN (
        SELECT  s2.occupation_id,
                CONCAT( s2.name, '|', s2.rate ORDER BY  rate DESC )
                      AS skills
            FROM (
                SELECT  hs.name, s1.rate, s1.occupation_id
                    FROM  occupation_skill_rate s1
                    INNER JOIN  hard_skills hs
                           ON s1.hard_skill_id = hs.id
                    ORDER BY  s.rate DESC
                    LIMIT  15 
                 ) AS s2
            GROUP BY  s2.occupation_id
            ORDER BY  s2.rate DESC
         ) AS s3  ON s2.occupation_id = t.id
    JOIN  ...
    JOIN  ... ;

Другой

Также есть способ построить длинный GROUP_CONCAT, а затем разрезать на 15 предметов с помощью SUBSTRING_INDEX(...).

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

Ajai rajan 09.10.2022 12:52

Я добавил еще...

Rick James 09.10.2022 17:51

Другие вопросы по теме