优化这个mysql查询

时间:2013-02-03 20:24:22

标签: mysql performance optimization

我想以某种方式加快这个问题。可能在可以接受的情况下在低流量站点上运行它。这需要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                  |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+

1 个答案:

答案 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