我有一张包含约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指数。有任何想法吗?我认为,这是让查询正常运行的最后一道障碍。再次感谢
答案 0 :(得分:0)
对数据进行少量选择性非规范化没有任何问题。如果你已经尽可能地使用索引&amp;子查询逻辑,您可以添加一个列,指示每个播放器的最新记录,然后添加包含该新列的索引。
如果您的应用在编写记录时知道哪条记录是最新的(即正在编写的记录是最新的?),这很容易做到。
如果由于某种原因无法完成,您可以让一个单独的流程不时检查数据并标记最新记录。
完整规范化在数据完整性方面非常出色,但数据最终变得足够大,以至于权衡不值得。所有大型在线服务(Facebook,Instagram等)都严重非规范化。
答案 1 :(得分:-2)
我无法想到更多有效的结果。子查询似乎非常适合,因为它缩小了结果集,并且它不依赖于主查询的列。
请记住在列名称,服务器和时间戳上有索引。
如果这不能与可接受的性能一起使用,您可以尝试单独使用EXPLAIN运行子查询。
如果它在某些时候使用filesort结束,则可能是键不适合可用内存。如果使用MyISAM作为引擎,可以尝试放大key_buffer_size,如果表使用InnoDB,则可以尝试放大innodb_buffer_pool_size,在mysql配置文件中。请注意,如果您的桌子不断增长,在某些时候您将再次遇到同样的问题,您将不得不寻找另一种解决方案(或购买更多内存,呵呵)。