MySQL查询性能改进按分组前的顺序排序

时间:2014-07-23 19:32:34

标签: mysql sql

下面是我用来获取serverID最新记录的查询,不幸的是,这个查询确实需要无休止的处理。根据下面的stackoverflow问题,它应该是一个非常快速的解决方案。有没有办法加快这个查询或我必须拆分它? (首先获取所有服务器ID而不是获取每个服务器的最后一条记录) Retrieving the last record in each group

SELECT s1.performance, s1.playersOnline, s1.serverID, s.name, m.modpack, m.color
    FROM stats_server s1 
    LEFT JOIN stats_server s2
        ON (s1.serverID = s2.serverID AND s1.id < s2.id)
    INNER JOIN server s
        ON s1.serverID=s.id
    INNER JOIN modpack m
        ON s.modpack=m.id
    WHERE s2.id IS NULL
    ORDER BY m.id
15 rows in set (34.73 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)

示例数据:

http://www.mediafire.com/download/n0blj1io0c503ig/mym_bridge.sql.bz2

4 个答案:

答案 0 :(得分:2)

修改

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

enter image description here 这是使用MAX()GROUP BY的快速查询,它提供相同的结果。请亲自试试。

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

enter image description here

答案 1 :(得分:1)

我会使用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
                 )

除了servermodpack上的主键索引(我假设在那里),您还需要stats_server(ServerId, id)上的索引。该索引还应该有助于您的查询版本。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

我猜你真的想要这个(注意连接的顺序和连接标准),这与你创建的索引相匹配:

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_server)。使用ORDER BY子句,MySQL可能希望以modpack开头,因此不必在以后对结果进行排序。

MySQL选择执行计划然后查看它是否具有正确的加入索引,而不是查看它必须加入的索引然后选择执行计划。 MySQL不仅会自动选择与您的索引匹配的计划。

STRAIGHT_JOIN告诉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

我不知道你已经定义了哪些索引,因为你没有提供EXPLAIN结果或显示你的索引,但这应该会让你知道如何改善这种情况。