2013-02-03 68 views
0

我正在寻找以某种方式加快此查询。可能达到可接受的程度,在低流量网站上运行它。这需要15+秒,这太长了。优化此mysql查询

目前表中有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 

Explain输出

+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+ 
| 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

编辑您的文章添加'explain query select ...'的输出,我会研究如何优化它。 – hd1

+0

已包括解释输出 – Wader

+0

你可以消除子查询以任何方式,形状或形式? – hd1

回答

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