我想以某种方式加快这个问题。可能在可以接受的情况下在低流量站点上运行它。这需要15秒以上,这太长了。
目前表中有13k行,大约是1个月的数据,但是我预计一旦网站投入生产,每月数据就会翻倍。目的是选择上周的前10名收益。
有两个表,用户表和跟踪表,在跟踪器表中,每个用户有多行,每个用户每天至少8行。
查询的目的是为每个用户获取最新的行,从1周前插入的行中减去该值,以获得他们获得的xp数量,并选择前10名获胜者。
表模式(我肯定也可以改进)
用户表
id int(11) primary
rsn varchar(12) unique
joined timestamp
disabled bool
跟踪表
id int(11) primary
user_id int(11) index /* Associated with the id in the users table */
timestamp timestamp
overall_rank int(11)
overall_level int(4)
overall_exp int(10)
查询。
SELECT `users`.`rsn` , `tracker`.`timestamp` , @uid := `tracker`.`user_id` , (
SELECT `overall_exp`
FROM `tracker`
WHERE `user_id` = @uid
ORDER BY `timestamp` DESC
LIMIT 1
) - (
SELECT `overall_exp`
FROM `tracker`
WHERE `timestamp` >= SUBDATE( NOW( ) , INTERVAL 1 WEEK )
AND `user_id` = @uid
ORDER BY `timestamp` ASC
LIMIT 1 ) AS `gained_exp`
FROM `tracker`
JOIN `users` ON `tracker`.`user_id` = `users`.`id`
ORDER BY `gained_exp` DESC
LIMIT 10
解释输出
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
| 1 | PRIMARY | users | index | PRIMARY | rsn | 14 | NULL | 71 | Using index; Using temporary; Using filesort |
| 1 | PRIMARY | tracker | ref | user_id | user_id | 4 | surreal.users.id | 103 | |
| 3 | UNCACHEABLE SUBQUERY | tracker | ALL | NULL | NULL | NULL | NULL | 11752 | Using where; Using filesort |
| 2 | UNCACHEABLE SUBQUERY | tracker | ALL | NULL | NULL | NULL | NULL | 11752 | Using where; Using filesort |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
答案 0 :(得分:1)
首先为所有用户查找今天和1周前的时间戳,然后再次连接到跟踪器以在进行计算之前找到相应的overall_exp值,尝试避免相关子查询:
SELECT rsn, ts.thisweek, ts.user_id,
last.overall_exp - previous.overall_exp AS gained_exp
FROM (SELECT user_id, MIN(timestamp) AS lastweek, MAX(timestamp) AS thisweek
FROM tracker
WHERE timestamp >= SUBDATE(NOW(), INTERVAL 1 WEEK)
GROUP BY user_id) AS ts
INNER JOIN tracker previous
ON previous.user_id = ts.user_id AND previous.timestamp = ts.lastweek
INNER JOIN tracker last
ON last.user_id = ts.user_id AND last.timestamp = ts.thisweek
JOIN users ON ts.user_id = users.id
ORDER BY gained_exp DESC
LIMIT 10