【问题标题】:Optimising this mysql query优化这个 mysql 查询
【发布时间】:2013-02-04 05:04:39
【问题描述】:

我希望以某种方式加快此查询的速度。可能达到在低流量站点上运行它可以接受的程度。它需要 15 秒以上,这太长了。

目前表中有 13k 行,大约是 1 个月的数据,但我预计一旦网站投入使用,每月数据会翻倍。目的是选择上周的前 10 名收益。

有两个表,users 表和 tracker 表,tracker 表中每个用户有多行,每个用户每天至少 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                  |
+----+----------------------+---------+-------+---------------+---------+---------+------------------+-------+----------------------------------------------+

【问题讨论】:

  • 编辑您的帖子以添加explain query select ... 的输出,我将研究如何优化它。
  • 已包含解释输出
  • 你能以任何方式、形状或形式消除子查询吗?
  • 在过去一天左右的时间里,我已经对此进行了一些调查,但是我无法理解它。根据我的发现,它应该有可能通过加入来实现
  • 您不需要 2 个子查询,一个就足够了。在您获得他上周拥有的 exp 的子查询中,您可以进行减法,因为您还拥有用户拥有的最后一个 exp。

标签: mysql performance optimization


【解决方案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

【讨论】:

    猜你喜欢
    • 2012-04-20
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2017-02-20
    • 1970-01-01
    相关资源
    最近更新 更多