order by在group by之前的MySQL查询性能改进

order by在group by之前的MySQL查询性能改进,mysql,sql,Mysql,Sql,下面是我用来根据serverID获取最新记录的一个查询,不幸的是,这个查询需要无限的时间来处理。根据下面的stackoverflow问题,这应该是一个非常快速的解决方案。是否有任何方法可以加快此查询的速度,或者我必须将其拆分?(首先获取所有服务器ID,然后获取每个服务器的最后一条记录) 样本输出: +------+-------------+-------+------+---------------+------+---------+------+------+----------+----

下面是我用来根据
serverID
获取最新记录的一个查询,不幸的是,这个查询需要无限的时间来处理。根据下面的stackoverflow问题,这应该是一个非常快速的解决方案。是否有任何方法可以加快此查询的速度,或者我必须将其拆分?(首先获取所有服务器ID,然后获取每个服务器的最后一条记录)

样本输出:

+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
|    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Impossible WHERE |
+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
1 row in set, 1 warning (0.00 sec)
+-------------+---------------+----------+---------------+-------------------------+--------+
| performance | playersOnline | serverID | name          | modpack                 | color  |
+-------------+---------------+----------+---------------+-------------------------+--------+
|          99 |            18 |       15 | hub           | Lobby                   | AAAAAA |
|          98 |            12 |       10 | horizons      | Horizons                | AA00AA |
|          97 |             6 |       11 | m_lobby       | Monster                 | AA0000 |
|          99 |             1 |       12 | m_north       | Monster                 | AA0000 |
|          86 |            10 |       13 | m_south       | Monster                 | AA0000 |
|          87 |            17 |       14 | m_east        | Monster                 | AA0000 |
|          98 |            10 |       16 | m_west        | Monster                 | AA0000 |
|          84 |             7 |        5 | tppi          | Test Pack Please Ignore | 55FFFF |
|          95 |            15 |        6 | agrarian_plus | Agrarian Skies          | 00AA00 |
|          98 |            23 |        7 | agrarian2     | Agrarian Skies          | 00AA00 |
|          74 |            18 |        9 | agrarian      | Agrarian Skies          | 00AA00 |
|          97 |            37 |       17 | agrarian3     | Agrarian Skies          | 00AA00 |
|          99 |            17 |        3 | bteam_pvp     | Attack of the B-Team    | FFAA00 |
|          73 |            44 |        8 | bteam_pve     | Attack of the B-Team    | FFAA00 |
|          93 |            11 |        4 | crackpack     | Crackpack               | EFEFEF |
+-------------+---------------+----------+---------------+-------------------------+--------+
15 rows in set (38.49 sec)
样本数据:

+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
|    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Impossible WHERE |
+------+-------------+-------+------+---------------+------+---------+------+------+----------+------------------+
1 row in set, 1 warning (0.00 sec)
+-------------+---------------+----------+---------------+-------------------------+--------+
| performance | playersOnline | serverID | name          | modpack                 | color  |
+-------------+---------------+----------+---------------+-------------------------+--------+
|          99 |            18 |       15 | hub           | Lobby                   | AAAAAA |
|          98 |            12 |       10 | horizons      | Horizons                | AA00AA |
|          97 |             6 |       11 | m_lobby       | Monster                 | AA0000 |
|          99 |             1 |       12 | m_north       | Monster                 | AA0000 |
|          86 |            10 |       13 | m_south       | Monster                 | AA0000 |
|          87 |            17 |       14 | m_east        | Monster                 | AA0000 |
|          98 |            10 |       16 | m_west        | Monster                 | AA0000 |
|          84 |             7 |        5 | tppi          | Test Pack Please Ignore | 55FFFF |
|          95 |            15 |        6 | agrarian_plus | Agrarian Skies          | 00AA00 |
|          98 |            23 |        7 | agrarian2     | Agrarian Skies          | 00AA00 |
|          74 |            18 |        9 | agrarian      | Agrarian Skies          | 00AA00 |
|          97 |            37 |       17 | agrarian3     | Agrarian Skies          | 00AA00 |
|          99 |            17 |        3 | bteam_pvp     | Attack of the B-Team    | FFAA00 |
|          73 |            44 |        8 | bteam_pve     | Attack of the B-Team    | FFAA00 |
|          93 |            11 |        4 | crackpack     | Crackpack               | EFEFEF |
+-------------+---------------+----------+---------------+-------------------------+--------+
15 rows in set (38.49 sec)

我将使用
不存在
来表达此查询:

SELECT ss.performance, ss.playersOnline, ss.serverID, s.name, m.modpack, m.color
FROM stats_server ss INNER JOIN
     server s
     ON ss.serverID = s.id INNER JOIN
     modpack m
     ON s.modpack = m.id
WHERE NOT EXISTS (select 1
                  from stats_server ss2
                  where ss2.serverID = ss.serverID AND ss2.id > ss.id
                 )

除了
服务器
modpack
上的主键索引(我假设它们在那里),您还需要
统计服务器(ServerId,id)
上的索引。此索引还应该有助于您的查询版本。

我将使用
not exists来表达此查询:

SELECT ss.performance, ss.playersOnline, ss.serverID, s.name, m.modpack, m.color
FROM stats_server ss INNER JOIN
     server s
     ON ss.serverID = s.id INNER JOIN
     modpack m
     ON s.modpack = m.id
WHERE NOT EXISTS (select 1
                  from stats_server ss2
                  where ss2.serverID = ss.serverID AND ss2.id > ss.id
                 )

除了
服务器
modpack
上的主键索引(我假设它们在那里),您还需要
统计服务器(ServerId,id)
上的索引。此索引还应该有助于您的查询版本。

我猜您确实需要此索引(请注意连接顺序和连接条件),并且此索引与您创建的索引相匹配:

SELECT s1.performance, s1.playersOnline, s1.serverID, s.name, m.modpack, m.color
  FROM server s
  INNER JOIN stats_server s1
    ON s1.serverID = s.id
  LEFT JOIN stats_server s2
    ON s2.serverID = s.id AND s2.id > s1.id
  INNER JOIN modpack m
    ON m.id = s.modpack
  WHERE s2.id IS NULL
  ORDER BY m.id
MySQL并不总是按照您在查询中写入表的顺序对表进行内部连接,因为顺序对结果集并不重要(尽管它会影响索引的使用)

WHERE
子句中没有指定可用索引的情况下,MySQL可能希望从行数最少的表开始(在这种情况下可能是stats\u server)。使用
orderby
子句,MySQL可能希望从modpack开始,这样以后就不必对结果进行排序

MySQL选择执行计划,然后查看是否有合适的索引用于加入,而不是查看必须加入哪些索引,然后选择执行计划。MySQL不会自动选择与索引匹配的计划

告诉MySQL连接表的顺序,以便使用您希望它使用的索引:

SELECT s1.performance, s1.playersOnline, s1.serverID, s.name, m.modpack, m.color
  FROM server s
  STRAIGHT_JOIN stats_server s1
    ON s1.serverID = s.id
  LEFT JOIN stats_server s2
    ON s2.serverID = s.id AND s2.id > s1.id
  STRAIGHT_JOIN modpack m
    ON m.id = s.modpack
  WHERE s2.id IS NULL
  ORDER BY m.id

我不知道您定义了什么索引,因为您没有提供
解释
结果或显示索引,但这应该会让您了解如何改善这种情况。

我猜您确实想要这样做(注意连接顺序和连接条件),并且这与您创建的索引相匹配:

SELECT s1.performance, s1.playersOnline, s1.serverID, s.name, m.modpack, m.color
  FROM server s
  INNER JOIN stats_server s1
    ON s1.serverID = s.id
  LEFT JOIN stats_server s2
    ON s2.serverID = s.id AND s2.id > s1.id
  INNER JOIN modpack m
    ON m.id = s.modpack
  WHERE s2.id IS NULL
  ORDER BY m.id
MySQL并不总是按照您在查询中写入表的顺序对表进行内部连接,因为顺序对结果集并不重要(尽管它会影响索引的使用)

WHERE
子句中没有指定可用索引的情况下,MySQL可能希望从行数最少的表开始(在这种情况下可能是stats\u server)。使用
orderby
子句,MySQL可能希望从modpack开始,这样以后就不必对结果进行排序

MySQL选择执行计划,然后查看是否有合适的索引用于加入,而不是查看必须加入哪些索引,然后选择执行计划。MySQL不会自动选择与索引匹配的计划

告诉MySQL连接表的顺序,以便使用您希望它使用的索引:

SELECT s1.performance, s1.playersOnline, s1.serverID, s.name, m.modpack, m.color
  FROM server s
  STRAIGHT_JOIN stats_server s1
    ON s1.serverID = s.id
  LEFT JOIN stats_server s2
    ON s2.serverID = s.id AND s2.id > s1.id
  STRAIGHT_JOIN modpack m
    ON m.id = s.modpack
  WHERE s2.id IS NULL
  ORDER BY m.id
我不知道您定义了哪些索引,因为您没有提供
解释结果或显示索引,但这应该会让您了解如何改善这种情况。

编辑

好的,我解决了。以下是显示原始慢速查询的展开行:

这里是一个使用
MAX()
groupby
的快速查询,它给出了相同的结果。请自己试一试

SELECT       s1.id 
            ,s1.performance
            ,s1.playersOnline
            ,s1.serverID 
            ,s.name 
            ,m.modpack
            ,m.color
FROM        stats_server s1
JOIN        (
    SELECT      MAX(id) as 'id'
    FROM        stats_server 
    GROUP BY    serverID
            ) AS s2
ON          s1.id = s2.id
JOIN        server s
ON          s1.serverID = s.id
JOIN        modpack m 
ON          s.modpack = m.id
ORDER BY    m.id
编辑

好的,我解决了。以下是显示原始慢速查询的展开行:

这里是一个使用
MAX()
groupby
的快速查询,它给出了相同的结果。请自己试一试

SELECT       s1.id 
            ,s1.performance
            ,s1.playersOnline
            ,s1.serverID 
            ,s.name 
            ,m.modpack
            ,m.color
FROM        stats_server s1
JOIN        (
    SELECT      MAX(id) as 'id'
    FROM        stats_server 
    GROUP BY    serverID
            ) AS s2
ON          s1.id = s2.id
JOIN        server s
ON          s1.serverID = s.id
JOIN        modpack m 
ON          s.modpack = m.id
ORDER BY    m.id

我是不是遗漏了什么?为什么标准的不相关子查询不起作用

SELECT x.id, x.performance, x.playersOnline, s.name, m.modpack, m.color, x.timestamp 
  FROM stats_server x 
  JOIN
     ( SELECT serverid, MAX(id) maxid FROM stats_server GROUP BY serverid ) y
    ON y.serverid = x.serverid AND y.maxid = x.id
  JOIN server s
    ON x.serverID=s.id
  JOIN modpack m
    ON s.modpack=m.id

我错过什么了吗?为什么标准的不相关子查询不起作用

SELECT x.id, x.performance, x.playersOnline, s.name, m.modpack, m.color, x.timestamp 
  FROM stats_server x 
  JOIN
     ( SELECT serverid, MAX(id) maxid FROM stats_server GROUP BY serverid ) y
    ON y.serverid = x.serverid AND y.maxid = x.id
  JOIN server s
    ON x.serverID=s.id
  JOIN modpack m
    ON s.modpack=m.id

发布查询的解释计划
explain SELECT s1.performance,s1.playersOnline,…。
@MKhalidJunaid kay,addedI我真的不明白为什么需要将stats_服务器表连接到自身。您没有引用任何列,当WHERE为NULL时,应该不需要小于限定符。尝试删除s2连接,使其中s1.id为NULL,并查看是否返回相同的数据我不确定mysql,但在其他数据库中,“WHERE s2.id为NULL”会将左侧连接更改为内部连接。这是使用Gordon方法的另一个原因。@user2693017,您在其中添加了解释计划?查询的解释计划后
explain SELECT s1.performance,s1.playersOnline,…。
@MKhalidJunaid kay,addedI真的不明白为什么需要将stats_服务器表连接到它本身。您没有引用任何列,当WHERE为NULL时,应该不需要小于限定符。尝试删除s2连接,使其中s1.id为NULL,并查看是否返回相同的数据我不确定mysql,但在其他数据库中,“WHERE s2.id为NULL”会将左侧连接更改为内部连接。这是使用Gordon方法的另一个原因。@user2693017,您在其中添加了解释计划?它们已经被索引了。我很难理解您的查询,我从未在不存在的地方使用过
,而且它不会返回任何结果。我应该导出一些测试数据吗?我同意索引(仍然取决于MySQL执行计划),但我不认为
WHERE NOT EXISTS
将如何改进此索引,因为它是一个依赖子查询。@MarcusAdams NOT every time EXISTS比left join快得多空,但有时它接管连接时经过了大量优化@user2693017。当你说“已编制索引”时,你的意思是有一个综合索引吗