简体   繁体   English

为什么我的查询在 MySQL 5.7 上需要超过 30 分钟,但在 MySQL 8 上需要几秒钟?

[英]Why does my query take over 30 mins on MySQL 5.7 but a couple seconds on MySQL 8?

I have the following query.我有以下查询。 On MySQL 5.7 it takes over 30 mins minutes to run but on MySQL 8 it takes less than 10 seconds.在 MySQL 5.7 上运行需要 30 多分钟,但在 MySQL 8 上运行时间不到 10 秒。 There are around 20k records in students_t, 500 in classes_t and 1100 in groups_t. student_t 中有大约 20k 条记录,classes_t 中有 500 条记录,groups_t 中有 1100 条记录。 student_enrolled_classes_t contains 100288 records and 160156 records.There are no foreign keys in place. student_enrolled_classes_t 包含 100288 条记录和 160156 条记录。没有外键。

SELECT DISTINCT
       s.forename
     , s.surname
     , count(c.id) as 'classes'
     , group_concat(DISTINCT g.name) 'groups'
  FROM students_t s
     , student_enrolled_classes_t c
     , student_enrolled_groups_t eg
     , groups_t g
 WHERE s.id = c.student_id
   AND s.id = eg.student_id
   AND eg.group_id = g.id
GROUP BY s.id, c.id
ORDER BY s.forename ASC;

The table structures are (generated with Hibernate):表结构(使用 Hibernate 生成):

CREATE TABLE classes_t 
(id BIGINT auto_increment PRIMARY KEY);

CREATE TABLE groups_t 
(id BIGINT auto_increment PRIMARY KEY
,name VARCHAR(255) NULL);

CREATE TABLE student_enrolled_classes_t
(id BIGINT auto_increment PRIMARY KEY
,class_id BIGINT NULL
,student_id BIGINT NULL);

CREATE TABLE student_enrolled_groups_t
(id BIGINT NOT NULL PRIMARY KEY
,group_id BIGINT NULL
,student_id BIGINT NULL);

CREATE TABLE students_t
(id BIGINT auto_increment PRIMARY KEY
,forename VARCHAR(255) NULL
,surname  VARCHAR(255) NULL);

The question is: Why does it take 30 mins on MySQL 5.7 but only 10 seconds on MySQL 8?问题是:为什么在 MySQL 5.7 上需要 30 分钟,而在 MySQL 8 上只需要 10 秒?

Thank you谢谢

You could write the query as follows.您可以按如下方式编写查询。 It uses newer join syntax and takes into a account situations where student is not part of a class/group.它使用较新的连接语法,并考虑到学生不属于班级/组的情况。

SELECT 
       s.forename
     , s.surname
     , count(distinct c.id) as 'classes'
     , group_concat(distinct g.name) 'groups'
  FROM students_t s
    LEFT JOIN student_enrolled_classes_t c ON c.student_id=s.id
    LEFT JOIN student_enrolled_groups_t eg ON eg.student_id=s.id
    LEFT JOIN groups_t g ON eg.group_id = g.id
GROUP BY s.id
ORDER BY s.forename ASC;

We need to see EXPLAIN SELECT... to analyze why one runs so slowly.我们需要看看EXPLAIN SELECT...来分析为什么一个人跑得这么慢。 While you are at it, also get EXPLAIN FORMAT=JSON SELECT... .当你在它的时候,也得到EXPLAIN FORMAT=JSON SELECT...

This reformulation and indexes may speed up the query on both servers, possibly making them both fast.这种重新制定和索引可以加快两台服务器上的查询,可能使它们都快。 Note that it gets rid of the GROUP BY and DISTINCT , both of which slow down the query.请注意,它摆脱了GROUP BYDISTINCT ,这两者都会减慢查询速度。

SELECT  s.forename, s.surname, 
        ( SELECT  COUNT(*)
            FROM  student_enrolled_classes_t
            WHERE  student_id = s.id 
        ) AS 'classes', 
        ( SELECT  GROUP_CONCAT(g.name)
                    FROM  student_enrolled_groups_t AS eg
                    JOIN  groups_t AS g  ON eg.group_id = g.id
                    WHERE  eg.student_id = s.id 
        ) AS 'groups'
    FROM  student_t AS s
    ORDER BY  s.forename ASC;

It seems that student_enrolled_groups_t is a many-to-many mapping table.似乎student_enrolled_groups_t是一个多对多映射表。 In that case, get rid of id and have these two indexes:在这种情况下,摆脱id并拥有这两个索引:

PRIMARY KEY(student_id, group_id)
INDEX(group_id, student_id)

When writing JOINs , please use the newer syntax involving ON -- for saying how the tables are 'related'.在编写JOINs时,请使用涉及ON的较新语法——用于说明表是如何“相关”的。 Filtering is done in WHERE .过滤在WHERE中完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM