0

我希望以某种方式加快这个查询。可能达到在低流量站点上运行它可以接受的程度。它需要 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                  |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+
4

1 回答 1

1

尝试通过首先找到所有用户的今天和 1 周前的时间戳来避免相关子查询,然后在进行计算之前再次加入两次跟踪器以找到相应的整体_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
于 2013-02-03T21:04:39.627 回答