2

当我第一次做这个查询并且表相对较小时,它运行得非常快,但随着时间的推移,随着更新表大小的增加(现在大约 6000 行),查询变得非常缓慢并且资源密集。我使用的服务器是来自 linode.com 的 1GB RAM VPS,实际上我没有等待足够长的时间来完成查询。

有趣的是,如果没有左连接中的额外条件 (SELECT MAX(u2.time)),它的运行时间 < 0.5 秒。

我在查询运行时查看了 mySQL 的进程列表,它一直显示为“正在发送数据”

这是查询:

SELECT 
  s.ID as sid, s.country AS country, 
  s.name AS name, s.ip AS ip, 
  u.connPlayers AS cp, u.maxPlayers AS mp
FROM servers AS s 

LEFT JOIN updates AS u 
  ON u.serverID = s.ID 
  AND u.time = 
      (SELECT MAX(u2.time) 
         FROM updates AS u2 
         WHERE u2.serverID = s.ID) 
ORDER BY RAND(MINUTE(NOW())) 
LIMIT 0,10

这是 my.cnf 文件:http ://redream.co.nz/my.cnf

表结构:

服务器表(20 行)

Field   Type
ID      int(10) Unique Key           
ip      varchar(200)                 
country varchar(2)               
name    varchar(600)             
motd    varchar(600)                 
desc    mediumtext               
version varchar(600)    

更新表(6000 行)

Field       Type
serverID    int(10)              
ping        int(10)              
time        int(14)              
uptime      int(10)              
connPlayers int(10)              
maxPlayers  int(10)              
uptime      int(14)
4

3 回答 3

2

子查询Select MAX(...正在为 的叉积updatesservers叉积的每一行运行serversupdates然后updates再次运行。MySQL 的优化器不是很复杂。

更新:我的 SQL 有点生疏,但你可以尝试这样的事情:

SELECT
  /* blah */
FROM
  servrs s
LEFT JOIN
  updates u
ON
  u.serverID = s.ID
GROUP BY s.serverID
HAVING MAX(u.time)

我手边没有 MySQL 实例,因此您可能需要稍微调整一下才能使其正常工作。

Update2:仔细看代码后,我觉得这个查询的成本比我原来的估计要大。更新了这个答案的顶部。

于 2012-06-11T01:00:19.087 回答
0

对于在您描述的平台上运行的 MySQL,6000 行是很小的。

我要检查的第一件事是您的 my.ini 文件。您是否使用了一种开箱即用的文件(现代服务器的配置不足)?如果是这种情况,最初的答案是编辑 my.ini 为 MySQL 分配合理数量的内存。

如果您需要这方面的帮助,请发布您的 my.ini 文件(减去任何密码),因为那里有许多可能导致这种类型的性能下降的事情。

此外,当查询运行得更快时(当行updates数少得多时),与当时的行数相比,您的查询将返回多少行updates

目前有多少行servers

于 2012-06-11T00:55:04.533 回答
0

我不是 MySQL 专家,但我认为这适用于 MySQL:

SELECT 
  s.ID as sid, s.country AS country, 
  s.name AS name, s.ip AS ip, 
  u.connPlayers AS cp, u.maxPlayers AS mp
FROM servers AS s 

LEFT JOIN (
    SELECT u.serverId, u.connPlayers, u.maxPlayers
    FROM updates u
    INNER JOIN (SELECT serverId, max(time) AS 'maxTime' FROM updates GROUP BY serverId) AS u2
        ON u.serverId = u2.serverId AND u.time = u2.maxTime 
) AS u ON u.serverID = s.ID 

ORDER BY RAND(MINUTE(NOW())) 
LIMIT 0,10

重要的变化是左连接现在包含以下子查询:

SELECT u.serverId, u.connPlayers, u.maxPlayers
FROM updates u
INNER JOIN (SELECT serverId, max(time) AS 'maxTime' FROM updates GROUP BY serverId) AS u2
    ON u.serverId = u2.serverId AND u.time = u2.maxTime 

此子查询再次包含一个子查询,并为每个 serverId 返回具有最大时间值的行。上面的子查询只执行一次,而不是交叉积中的每一行。

于 2012-06-11T01:38:32.143 回答