选择每个玩家的最新记录并订购(性能问题)

时间:2014-01-31 20:46:41

标签: mysql database

我有一张包含约300,000条记录的表格,我想为每位玩家选择最新记录并按评级订购。下面的查询给出了我想要的结果,但是在300,000条记录的表上运行需要大约100秒,表格将增长到数百万条记录。

SELECT *
FROM players a
JOIN (
    SELECT name, server, Max(timestamp) AS MaxTimeStamp
    FROM players
    GROUP BY name, server
) b
ON a.name = b.name
AND a.server = b.server
AND a.timestamp = b.MaxTimeStamp
ORDER BY score desc

执行计划如下:

id  select_Type table           type    possible_keys  key      key_length  ref                             rows    extra
1   PRIMARY     <derived2>      ALL                                                                         268683  Using temporary; Using filesort
1   PRIMARY     a               eq_ref  PRIMARY        PRIMARY  147         b.MaxTimeStamp,b.server,b.name  1   
2   DERIVED     players_temp    index                  PRIMARY  147                                         264813  Using index; Using temporary; Using filesort

主键是'timestamp','server','name'。 “得分”已编入索引如果有更多信息可以提供帮助,请与我们联系。非常感谢!

修改

创建表格当前表格的表格(我已经多次改变了!)如下:

    CREATE TABLE `players` (
      `timestamp` datetime NOT NULL,
      `server` varchar(25) NOT NULL,
      `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `normName` varchar(20) DEFAULT NULL,
      `position` varchar(20) DEFAULT NULL,
      `team` varchar(10) DEFAULT NULL,
      `won` smallint(6) DEFAULT NULL,
      `lost` smallint(6) DEFAULT NULL,
      `score` smallint(6) DEFAULT NULL,
      `picture` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`timestamp`,`server`,`name`),
      KEY `normName` (`normName`) USING BTREE,
      KEY `score` (`score`) USING BTREE,
      KEY `playerRecord` (`timestamp`,`server`,`name`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

innodb_buffer_pool_size已设置为1GB,但性能仍然不佳。子查询单独运行需要20秒。我做了一个解释:

EXPLAIN 
SELECT name, server, Max(timestamp) AS MaxTimeStamp
FROM players_temp
GROUP BY name, server

结果:

1   SIMPLE  players_temp    index       rating2v2   3       265910  Using index; Using temporary; Using filesort

编辑2

通过在子查询中更改GROUP BY,我得到了更多。我将它从'GROUP BY name,server'更改为'GROUP BY timestamp,server,name'以匹配键的顺序,现在它使用索引而不是filesort临时表,但是仍然存在问题,它似乎是按分数排序。

如果我运行此查询:

SELECT *
FROM players_temp a
ORDER BY a.score

运行需要33秒,EXPLAIN表示它正在使用filesort。如上面的CREATE语句所示,得分上有BTREE指数。有任何想法吗?我认为,这是让查询正常运行的最后一道障碍。再次感谢

2 个答案:

答案 0 :(得分:0)

对数据进行少量选择性非规范化没有任何问题。如果你已经尽可能地使用索引&amp;子查询逻辑,您可以添加一个列,指示每个播放器的最新记录,然后添加包含该新列的索引。

如果您的应用在编写记录时知道哪条记录是最新的(即正在编写的记录是最新的?),这很容易做到。

如果由于某种原因无法完成,您可以让一个单独的流程不时检查数据并标记最新记录。

完整规范化在数据完整性方面非常出色,但数据最终变得足够大,以至于权衡不值得。所有大型在线服务(Facebook,Instagram等)都严重非规范化。

答案 1 :(得分:-2)

我无法想到更多有效的结果。子查询似乎非常适合,因为它缩小了结果集,并且它不依赖于主查询的列。

请记住在列名称,服务器和时间戳上有索引。

如果这不能与可接受的性能一起使用,您可以尝试单独使用EXPLAIN运行子查询。

如果它在某些时候使用filesort结束,则可能是键不适合可用内存。如果使用MyISAM作为引擎,可以尝试放大key_buffer_size,如果表使用InnoDB,则可以尝试放大innodb_buffer_pool_size,在mysql配置文件中。请注意,如果您的桌子不断增长,在某些时候您将再次遇到同样的问题,您将不得不寻找另一种解决方案(或购买更多内存,呵呵)。